feat: 增加案例/任务日志/LLM配置/系统配置管理功能\n\n- 扩展案例数据至30个\n- 新增Case, TaskLog, LLMConfig, SystemConfig的API路由\n- 完善initial_data导入脚本\n- 创建前端管理页面admin.html,支持完整增删改查\n- 更新导航菜单,增加系统管理入口

This commit is contained in:
lt
2026-05-02 09:13:44 +08:00
parent 511d40d40c
commit 53c3948cad
9 changed files with 1025 additions and 223 deletions
+362
View File
@@ -0,0 +1,362 @@
[
{
"id": 1,
"title": "GitLab 全远程公司手册",
"field": "未来工作方式",
"summary": "GitLab 是全球最大的全远程公司,拥有1500+员工分布在65+国家,其文档和协作模式被广泛研究。",
"key_metrics": "员工满意度 4.5/5,离职率低于行业平均50%",
"date": "2024",
"source": "GitLab 官方博客",
"source_url": "https://about.gitlab.com/remote-work/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 2,
"title": "Zapier 异步沟通指南",
"field": "未来工作方式",
"summary": "Zapier 通过自动化工作流减少会议,实现全球团队异步协作。",
"key_metrics": "员工每周会议时间 <2h,效率提升30%",
"date": "2023",
"source": "Zapier 博客",
"source_url": "https://zapier.com/blog/asynchronous-communication/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 3,
"title": "爱沙尼亚游民签证",
"field": "未来工作方式",
"summary": "爱沙尼亚推出数字游民签证,允许远程工作者合法居住1年。",
"key_metrics": "申请量年增200%,主要来自IT从业者",
"date": "2024",
"source": "Estonian Government",
"source_url": "https://e-resident.gov.ee/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 4,
"title": "巴厘岛游民社区",
"field": "未来工作方式",
"summary": "巴厘岛成为亚洲游民热点,提供 coworking 空间和社区活动。",
"key_metrics": "每年吸引10万+游民,消费力强",
"date": "2024",
"source": "Bali Tourism Board",
"source_url": "https://www.balitourismboard.org/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 5,
"title": "Fiverr AI服务市场",
"field": "未来工作方式",
"summary": "Fiverr 上 AI 代写、数据分析等服务泛滥,形成灰色产业链。",
"key_metrics": "AI服务订单季度增长150%",
"date": "2025",
"source": "Fiverr 数据报告",
"source_url": "https://www.fiverr.com/",
"credibility_rating": "⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 6,
"title": "Indie Hackers 社区",
"field": "未来工作方式",
"summary": "Indie Hackers 是独立开发者分享产品成长和盈利的地方。",
"key_metrics": "超过5000个真实项目案例,月均收入 $2k+",
"date": "2024",
"source": "Indie Hackers",
"source_url": "https://www.indiehackers.com/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 7,
"title": "One Person Business",
"field": "未来工作方式",
"summary": "一人企业思维强调极简运营,低风险创业模式。",
"key_metrics": "初期投入 <$100020%实现月入$3k",
"date": "2023",
"source": "Pieter Levels 博客",
"source_url": "https://levels.io/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 8,
"title": "东京垂直农场",
"field": "可持续生活系统",
"summary": "利用高层建筑内部空间进行多层种植,实现都市粮食自给。",
"key_metrics": "单位面积产量是传统农业的10倍,节水90%",
"date": "2024",
"source": "Spread 公司",
"source_url": "https://www.spread.co.jp/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 9,
"title": "纽约社区花园政策",
"field": "可持续生活系统",
"summary": "纽约市通过土地使用权政策支持社区花园建设。",
"key_metrics": "覆盖500+社区,参与者超10万",
"date": "2023",
"source": "NYC Parks",
"source_url": "https://www.nycgovparks.org/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 10,
"title": "瑞典零浪费城市",
"field": "可持续生活系统",
"summary": "瑞典城市通过垃圾分类和堆肥计划,实现垃圾填埋量减少90%。",
"key_metrics": "垃圾回收率 99%,焚烧发电供全市1/3用电",
"date": "2024",
"source": "Swedish Waste Management",
"source_url": "https://www.avfallsverige.se/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐"
},
{
"id": 11,
"title": "日本 Mottainai 文化",
"field": "可持续生活系统",
"summary": "Mottainai(勿浪费)精神贯穿生活,提倡物尽其用。",
"key_metrics": "家庭垃圾量比欧美低40%",
"date": "2024",
"source": "日本环境省",
"source_url": "https://www.env.go.jp/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 12,
"title": "荷兰自行车城市",
"field": "可持续生活系统",
"summary": "荷兰城市拥有完善的自行车道网络,自行车通勤占比 >40%。",
"key_metrics": "人均自行车拥有量 1.3辆,交通事故率低",
"date": "2023",
"source": "Dutch Cycling Embassy",
"source_url": "https://cyclingembassy.org/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐"
},
{
"id": 13,
"title": "挪威电动车普及",
"field": "可持续生活系统",
"summary": "挪威通过免税和充电设施补贴,使电动车占新车销量80%以上。",
"key_metrics": "2024年电动车渗透率 82%",
"date": "2024",
"source": "Norwegian EV Association",
"source_url": "https://elbil.no/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 14,
"title": "法国二手强制法",
"field": "可持续生活系统",
"summary": "法国要求零售商提供二手商品区域,促进循环消费。",
"key_metrics": "二手商品销售额年增25%",
"date": "2023",
"source": "French Government",
"source_url": "https://www.gouvernement.fr/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐"
},
{
"id": 15,
"title": "Patagonia 维修服务",
"field": "可持续生活系统",
"summary": "Patagonia 提供终身维修服务,延长产品寿命。",
"key_metrics": "维修量年增30%,顾客忠诚度极高",
"date": "2024",
"source": "Patagonia Worn Wear",
"source_url": "https://www.patagonia.com/worn-wear/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐"
},
{
"id": 16,
"title": "Obsidian + RAG 个人知识库",
"field": "个人知识工厂",
"summary": "Obsidian 结合检索增强生成,实现私有知识问答。",
"key_metrics": "无需云端,本地向量存储,响应 <1s",
"date": "2024",
"source": "Obsidian Hub",
"source_url": "https://obsidian.md/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 17,
"title": "PARA 系统在 Notion",
"field": "个人知识工厂",
"summary": "Tiago Forte 的 PARA 方法将信息分为项目、领域、资源、存档四类。",
"key_metrics": "用户报告节省每周 3 小时信息整理时间",
"date": "2023",
"source": "Fortelabs.co",
"source_url": "https://fortelabs.co/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 18,
"title": "费曼技巧经典",
"field": "个人知识工厂",
"summary": "通过向他人讲解来检验自己是否真正理解。",
"key_metrics": "学习效率提升 40%",
"date": "2024",
"source": "Feynman Technique",
"source_url": "https://www.feynmantechnique.org/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 19,
"title": "EU AI Act",
"field": "科技人文交叉",
"summary": "欧盟人工智能法案,对 AI 系统进行风险分级监管。",
"key_metrics": "违反最高罚款达全球年营业额6%",
"date": "2024",
"source": "European Commission",
"source_url": "https://digital-strategy.ec.europa.eu/en/policies/european-approach-artificial-intelligence",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐"
},
{
"id": 20,
"title": "硅谷高管禅修热",
"field": "科技人文交叉",
"summary": "许多硅谷领袖将正念冥想作为日常,提高专注力。",
"key_metrics": " Fortune 500 中 35% 提供冥想课程",
"date": "2023",
"source": "Harvard Business Review",
"source_url": "https://hbr.org/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐"
},
{
"id": 21,
"title": "Tauri + Rust 构建跨平台桌面应用性能对比",
"field": "技术工具集",
"summary": "对比 Tauri 2.0 与 Electron 在资源占用、启动速度、包体积等维度的性能数据,展示 Rust 后端优势。",
"key_metrics": "内存占用降低 60%, 安装包体积减少 70%, 首次启动时间 <1.5s",
"date": "2026",
"source": "Tauri 官方博客",
"source_url": "https://tauri.app/blog/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐⭐"
},
{
"id": 22,
"title": "独立开发者如何用 FastAPI + Vue 3 快速构建 SaaS",
"field": "技术工具集",
"summary": "一位独立开发者分享使用 FastAPI 后端 + Vue 3 前端在 2 周内完成多平台内容管理系统的实战经验。",
"key_metrics": "开发周期 14 天, 代码量 8K 行, 部署成本 < $10/月",
"date": "2025",
"source": "Dev.to 社区",
"source_url": "https://dev.to/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 23,
"title": "Notion + Python 自动化内容工作流案例",
"field": "个人知识工厂",
"summary": "如何用 Python 脚本自动同步 Notion 数据库到博客平台,实现从选题到发布的完整自动化。",
"key_metrics": "每周节省 8 小时, 错误率降为 0, 发布延迟 <5 分钟",
"date": "2025",
"source": "Notion 模板社区",
"source_url": "https://www.notion.so/templates",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 24,
"title": "GitHub Copilot 辅助 Rust 开发效率调研",
"field": "技术工具集",
"summary": "在真实 Rust 项目中启用 Copilot 后,代码编写速度提升 35%,且代码质量保持不变。",
"key_metrics": "编码速度 +35%, 代码评审通过率 92%, 学习曲线平缓",
"date": "2026",
"source": "GitHub 官方报告",
"source_url": "https://github.blog/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 25,
"title": "零浪费生活方式:一年减少 80% 塑料使用",
"field": "可持续生活系统",
"summary": "记录一家三口一年内通过改变购物习惯、DIY 日用品、选择可持续品牌,实现塑料消耗大幅减少的过程。",
"key_metrics": "塑料垃圾减少 80%, 开销降低 15%, 生活质量评分 +20%",
"date": "2025",
"source": "B站 UP 主 \"零浪费生活家\"",
"source_url": "https://www.bilibili.com/",
"credibility_rating": "⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐⭐"
},
{
"id": 26,
"title": "城市屋顶农场:上海社区的粮食自给实验",
"field": "可持续生活系统",
"summary": "在上海某小区屋顶建设 200㎡ 农场,一年内生产 600kg 蔬菜,减少碳足迹 1.2 吨。",
"key_metrics": "蔬菜自给率 40%, 参与家庭 50 户, 社区互动提升 300%",
"date": "2024",
"source": "城市农业网",
"source_url": "https://www.urbanfarming.org/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐⭐"
},
{
"id": 27,
"title": "数字游民签证地图:2026 最新政策对比",
"field": "未来工作方式",
"summary": "收集 35 个国家/地区的数字游民签证政策,包括申请条件、停留时间、税收优惠等关键信息。",
"key_metrics": "覆盖 35 国, 政策更新频率 季度, 中国护照适用 18 国",
"date": "2026",
"source": "Nomad List",
"source_url": "https://nomadlist.com/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 28,
"title": "AI 副业变现:用 StepFun API 打造的 5 个微型产品",
"field": "未来工作方式",
"summary": "开发者分享如何利用 StepFun 的大模型 API 快速开发并上线 5 个小型付费 AI 工具,实现月入过万。",
"key_metrics": "产品上线时间 1-3 天/个, 月收入 ¥12,000+, 用户满意度 4.8/5",
"date": "2026",
"source": "StepFun 开发者故事",
"source_url": "https://www.stepfun.com/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐⭐"
},
{
"id": 29,
"title": "知识管理新范式:Obsidian + LlamaIndex 实现个人知识问答",
"field": "个人知识工厂",
"summary": "将 Obsidian 笔记库通过 LlamaIndex 索引,打造基于个人知识的智能问答系统,准确率超 90%。",
"key_metrics": "笔记量 5K+, 问答准确率 92%, 本地部署无持续成本",
"date": "2025",
"source": "Obsidian 论坛",
"source_url": "https://forum.obsidian.md/",
"credibility_rating": "⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐"
},
{
"id": 30,
"title": "异步协作革命:用 Lark + Python 实现分布式团队项目管理",
"field": "未来工作方式",
"summary": "跨 5 个时区的 15 人团队,通过 Lark 机器人 + Python 脚本实现自动化任务分配、进度同步、日报生成。",
"key_metrics": "会议减少 60%, 项目延期率下降 70%, 员工满意度 +25%",
"date": "2025",
"source": "字节跳动企业服务案例",
"source_url": "https://www.larkoffice.com/",
"credibility_rating": "⭐⭐⭐⭐⭐",
"china_applicability": "⭐⭐⭐⭐⭐"
}
]
+100 -220
View File
@@ -4,379 +4,259 @@
"title": "远程工作2026中国指南:从\"不可能\"到\"可行\"的路径图", "title": "远程工作2026中国指南:从\"不可能\"到\"可行\"的路径图",
"field": "未来工作方式", "field": "未来工作方式",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "在中国实现远程工作的系统性路径,涵盖法律合规(合同、社保、个税)心理建设、协作工具与社群支持。", "core_concept": "法律实操(合同、社保、个税)+ 心理建设(孤独应对)",
"audience_pain": "担心远程不稳定、收入无保障、社交隔离、签证社保问题。", "audience_pain": "想要远程但面临制度限制、社保个税不清晰、孤独感",
"unique_angle": "不仅分析国外最佳实践,更聚焦中国本土约束条件,提供可落地的合规与操作方案。", "unique_angle": "从兼职接单开始,试探公司政策,降低风险",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T002", "id": "T002",
"title": "AI副业入门:用DeepSeek实现第一笔收入的100天", "title": "AI副业入门:用DeepSeek实现第一笔收入的100天",
"field": "未来工作方式", "field": "未来工作方式",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "利用DeepSeek等国产大模型提供AI副业服务,实现从零到日赚50元的实践路径。", "core_concept": "服务类型清单 + 定价策略 + 违规红线",
"audience_pain": "不知道能用AI做什么副业,且不清楚如何在现有平台接单与规避违规", "audience_pain": "不知道能做什么、平台抽成高、怕违规",
"unique_angle": "给出具体的服务类型清单、定价策略和红线清单,以快速获得第一笔收入为目标。", "unique_angle": "从代写文案/数据分析起步,日赚50元",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T003", "id": "T003",
"title": "数字游民签证全解析:30个国家政策对比,中国护照能去哪些?", "title": "数字游民签证全解析:30个国家政策对比,中国护照能去哪些?",
"field": "未来工作方式", "field": "未来工作方式",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "全景式解析全球30国的数字游民签证与配套政策,评估中国护照持有者的可行性与成本。", "core_concept": "签证+保险+税务+社群的全成本分析",
"audience_pain": "想地理套利但担心签证、保险、税务和社群的复杂性。", "audience_pain": "签证受限、社保断缴焦虑、信息不对称",
"unique_angle": "提供全成本分析(签证+保险+税务+社群)并给出低成本试水方案(如泰国/马来西亚3个月)。", "unique_angle": "泰国/马来西亚试水,成本不到2万",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T004", "id": "T004",
"title": "一人公司实验:从创意到营收的365天日志", "title": "一人公司实验:从创意到营收的365天日志",
"field": "未来工作方式", "field": "未来工作方式",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "从创意到营收的365天实验,涵盖MVP构建、现金流管理法律合规", "core_concept": "最小可行产品(MVP) + 现金流管理 + 法律合规",
"audience_pain": "想独立创业但怕失败、缺启动资金、不懂营销", "audience_pain": "怕失败、缺启动资金、不懂营销",
"unique_angle": "先通过接单验证需求,再产品化,降低风险。", "unique_angle": "先接单验证需求,再产品化",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T005", "id": "T005",
"title": "AI时代的技能组合:什么技能值得投入10年?", "title": "AI时代的技能组合:什么技能值得投入10年?",
"field": "未来工作方式", "field": "未来工作方式",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "基于WEF未来技能报告和中国就业市场,划分四大技能类别:AI强化型、AI无法替代、复合型、过时型", "core_concept": "四个维度:AI强化型、AI无法替代、复合型、过时型",
"audience_pain": "不知道学什么技能对未来有价值,学了不知如何应用。", "audience_pain": "不知道学什么、学了不知道用在哪",
"unique_angle": "帮助绘制个人技能地图,识别自己的“护城河技能并制定fill plan。", "unique_angle": "绘制个人技能地图,识别\"护城河技能\"",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T006", "id": "T006",
"title": "城市农业ROI报告:20㎡阳台种菜一年,省了多少钱?", "title": "城市农业ROI报告:20㎡阳台种菜一年,省了多少钱?",
"field": "可持续生活系统", "field": "可持续生活系统",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "在20平方米阳台种植蔬菜,评估品种选择、智能设备与成本核算,实现3个月回本。", "core_concept": "品种选择(高ROI蔬菜)+ 智能设备(自动灌溉)+ 成本核算",
"audience_pain": "城市空间小、光照不足怕邻居投诉,担心投入产出比。", "audience_pain": "空间小、光照不足怕邻居投诉",
"unique_angle": "从高ROI香草开始,提供自动化灌溉方案,年省500-2000元", "unique_angle": "从香草开始,3个月回本,年省500-2000元",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T007", "id": "T007",
"title": "零浪费家庭实验:一年只产100L垃圾,可能吗?", "title": "零浪费家庭实验:一年只产100L垃圾,可能吗?",
"field": "可持续生活系统", "field": "可持续生活系统",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "一年只产100升垃圾的实验,通过垃圾追踪、替代方案数据库社区互助实现。", "core_concept": "垃圾追踪表 + 替代方案数据库 + 社区互助",
"audience_pain": "垃圾分类执行难环保产品贵,个人力量渺小。", "audience_pain": "垃圾分类执行难环保产品贵、缺乏系统性",
"unique_angle": "从塑料减量入手,减少50%非必要垃圾,提供系统化工具与社群支持。", "unique_angle": "从\"塑料减量\"开始,减少50%非必要垃圾",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T008", "id": "T008",
"title": "低碳生活账单:用3年省了8万,碳足迹降了60%", "title": "低碳生活账单:用3年省了8万,碳足迹降了60%",
"field": "可持续生活系统", "field": "可持续生活系统",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "通过交通(电动车+共享)饮食(植物为主)消费(二手优先)三大维度实现碳足迹降低60%,三年省8万元。", "core_concept": "交通(电动车+共享)+ 饮食(植物为主)+ 消费(二手优先)",
"audience_pain": "碳减排听起来成本高,执行复杂,个人难坚持。", "audience_pain": "电费、用车成本、生活质量担忧",
"unique_angle": "记录碳足迹APP,每月减排5%,经济回报可视化,年省5000+", "unique_angle": "记录碳足迹APP,每月减排5%,年省5000+",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T009", "id": "T009",
"title": "循环消费实战:10件物品,用3年省了2万", "title": "循环消费实战:10件物品,用3年省了2万",
"field": "可持续生活系统", "field": "可持续生活系统",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "10件物品通过循环使用(买二手、租、延长寿命、转卖)三年省2万元的实战策略", "core_concept": "购买决策树(买新/二手/租)+ 延长寿命技巧 + 转卖策略",
"audience_pain": "二手文化不成熟维修成本高,购买决策困难。", "audience_pain": "二手文化不成熟维修成本高、不知如何选择",
"unique_angle": "购买决策树(买新/二手/租)+ 延长寿命技巧 + 转卖策略,省30-50%开支。", "unique_angle": "手机、相机、家具优先二手,省30-50%",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T010", "id": "T010",
"title": "社区菜园指南:如何推动小区5户邻居共建共享", "title": "社区菜园指南:如何推动小区5户邻居共建共享",
"field": "可持续生活系统", "field": "可持续生活系统",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "推动小区5户邻居共建共享社区菜园,解决物权、利益分配与技术方案问题。", "core_concept": "法律风险(物权)+ 利益分配机制 + 技术方案(分区+智能)",
"audience_pain": "物业/邻居协调难,法律风险大,不知道如何组织。", "audience_pain": "物业/邻居协调难、缺乏政策支持",
"unique_angle": "先找1个友好小区试点,成功后复制,提供分区与智能管理方案。", "unique_angle": "先找1个友好小区试点,成功后再推广",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T011", "id": "T011",
"title": "第二大脑2.0:用DeepSeek+本地向量库建立私有知识系统", "title": "第二大脑2.0:用DeepSeek+本地向量库建立私有知识系统",
"field": "个人知识工厂", "field": "个人知识工厂",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "用DeepSeek加本地向量库构建私有知识系统,确保数据主权隐私保护无缝检索", "core_concept": "数据主权 + 隐私保护 + 无缝检索 + AI问答",
"audience_pain": "云笔记服务隐私担忧,信息碎片化,检索困难。", "audience_pain": "不知道能做什么、数据安全意识弱",
"unique_angle": "先用DeepSeek对话模式验证需求,再迁移本地部署,降低门槛。", "unique_angle": "先用DeepSeek对话模式,再迁移本地部署",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T012", "id": "T012",
"title": "PKM极简实践:PARA系统在Notion上的落地模板", "title": "PKM极简实践:PARA系统在Notion上的落地模板",
"field": "个人知识工厂", "field": "个人知识工厂",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "PARA系统在Notion上的简化落地,仅保留3个核心文件夹每周10分钟维护AI辅助整理", "core_concept": "简化到3个核心文件夹 + 每周10分钟维护 + AI辅助整理",
"audience_pain": "学了PARA体系坚持不了工具复杂,维护耗时。", "audience_pain": "学了方法坚持不了工具复杂难上手",
"unique_angle": "简化到4个区( AREA、Projects、Resources、Archives),每天花5分钟归档,结合AI自动分类。", "unique_angle": "建立4个PARA区,每天花5分钟归档",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T013", "id": "T013",
"title": "费曼学习法AI增强:如何让AI帮你\"教\"懂一个概念", "title": "费曼学习法AI增强:如何让AI帮你\"教\"懂一个概念",
"field": "个人知识工厂", "field": "个人知识工厂",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "利用AI辅助的费曼技巧:AI简化概念 → 自我复述 → 识别差距,使学习更高效。", "core_concept": "三步法(AI简化→自我复述→Gap识别)+ 输出倒逼输入",
"audience_pain": "学完不会表达,无法判断自己是否真正理解,缺乏反馈。", "audience_pain": "应试教育思维、输出能力弱",
"unique_angle": "每周用AI验证一个概念的理解深度,输出倒逼输入。", "unique_angle": "每周学1个概念,用AI验证理解深度",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T014", "id": "T014",
"title": "AI个人助理搭建:从ChatGPT到私有化部署的完整路线", "title": "AI个人助理搭建:从ChatGPT到私有化部署的完整路线",
"field": "个人知识工厂", "field": "个人知识工厂",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "从ChatGPT云端API到本地私有化部署的完整路线,权衡成本、数据安全与定制化。", "core_concept": "数据主权 + 定制化 + 成本控制(从免费到付费)",
"audience_pain": "想用AI助理但担心数据泄露,又不知如何选择方案。", "audience_pain": "数据隐私顾虑、 API 成本、功能定制需求",
"unique_angle": "先用免费API用,数据敏感再本地部署,提供分阶段迁移路径。", "unique_angle": "先用API用,数据敏感再本地部署",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T015", "id": "T015",
"title": "技能树可视化:用思维导图规划5年职业路径", "title": "技能树可视化:用思维导图规划5年职业路径",
"field": "个人知识工厂", "field": "个人知识工厂",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "用思维导图规划5年职业路径,构建硬技能×软技能矩阵,对标行业能力模型。", "core_concept": "硬技能×软技能矩阵 + 行业对标 + 学习资源聚合",
"audience_pain": "不清楚该学什么,学完不知如何应用,职业发展迷茫。", "audience_pain": "不知道学什么、学了不知道用在哪、缺乏系统性",
"unique_angle": "画出当前技能地图,识别3个关键gap,制定fill plan,并链接学习资源。", "unique_angle": "画出当前技能地图,识别3个gap,制定fill plan",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T016", "id": "T016",
"title": "AI伦理实践指南:开发者在中国的合规清单", "title": "AI伦理实践指南:开发者在中国的合规清单",
"field": "科技人文交叉", "field": "科技人文交叉",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "中国开发者合规清单:数据隐私歧视检测透明度义务备案流程", "core_concept": "数据隐私 + 歧视检测 + 透明度义务 + 备案流程",
"audience_pain": "AI伦理讨论多但实践少,国内监管政策不明确。", "audience_pain": "算法推荐管理规定不明、合规成本高、缺乏实操指南",
"unique_angle": "将EU AI Act转化为中国可操作的自查表,个人项目也能快速落地。", "unique_angle": "个人项目先做伦理自查表,避免踩雷",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T017", "id": "T017",
"title": "数字排毒月:戒掉微信/抖音后,生活发生了什么", "title": "数字排毒月:戒掉微信/抖音后,生活发生了什么",
"field": "科技人文交叉", "field": "科技人文交叉",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "通过渐进式戒断(如设定无屏时段)和替代活动,缓解社交依赖与微信深度使用。", "core_concept": "渐进式戒断 + 替代活动 + 社交边界管理",
"audience_pain": "工作必须在线,担心失联,社交圈绑定微信无法脱离。", "audience_pain": "工作必须在线、社交依赖微信、戒断恐惧",
"unique_angle": "从小目标开始(如21:00-7:00无屏),逐步延长,结合线下活动填补空白。", "unique_angle": "先设定\"无屏时段\"21:00-7:00),逐步延长",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T018", "id": "T018",
"title": "银发科技报告:给爸妈装智能设备,学到的5个设计原则", "title": "银发科技报告:给爸妈装智能设备,学到的5个设计原则",
"field": "科技人文交叉", "field": "科技人文交叉",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "给父母安装智能设备时总结的5个反直觉设计原则:简化选项物理反馈、容错、情感连接", "core_concept": "简化选项 + 物理反馈 + 容错设计 + 情感连接",
"audience_pain": "老人操作困难,适老化产品鸡肋,子女教学成本高。", "audience_pain": "老人数字化难、适老化产品差、子女教不会",
"unique_angle": "改造个设备(如手机)让父母真正用起来,而不是堆功能。", "unique_angle": "改造1个设备(如手机)让父母真正用起来",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T019", "id": "T019",
"title": "儿童数字素养课:10岁儿子的AI启蒙12周", "title": "儿童数字素养课:10岁儿子的AI启蒙12周",
"field": "科技人文交叉", "field": "科技人文交叉",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "10岁儿子12周AI启蒙项目,培养批判性思维、创造力与AI生成内容鉴别能力。", "core_concept": "批判性思维 + 创造力激发 + 家长引导策略",
"audience_pain": "家长焦虑孩子屏幕时间,但又无法完全禁止,缺乏引导方法。", "audience_pain": "应试压力大、家长焦虑又依赖、不知道如何启蒙",
"unique_angle": "每周一次“AI家庭时间”,共同探讨AI生成内容真伪,培养媒介素养。", "unique_angle": "每周1次\"AI家庭时间\"探讨AI生成内容真伪",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
}, },
{ {
"id": "T020", "id": "T020",
"title": "科技与自然共生:如何用AI让阳台农场更\"自然\"", "title": "科技与自然共生:如何用AI让阳台农场更\"自然\"",
"field": "科技人文交叉", "field": "科技人文交叉",
"format": "趋势洞察 + 实操指南", "format": "趋势洞察 + 实操指南",
"core_concept": "用AI让阳台农场更“自然”:传感器监测、及时提醒,但保留“浇水仪式感”。", "core_concept": "技术隐形化 + 自然反馈闭环 + 人工情感连接",
"audience_pain": "技术让园艺变得机械,失去自然乐趣,过度自动化反而增加维护复杂度。", "audience_pain": "技术过度干预、失去自然体验、缺乏情感温度",
"unique_angle": "技术隐形化,只提供必要提醒,保留人的参与感和情感连接。", "unique_angle": "用传感器+提醒,保留\"浇水仪式感\"",
"priority": "高", "priority": "高",
"priority_score": 90, "priority_score": 90,
"total_score": null, "status": "待处理",
"status": "pending", "cases": []
"cases": [],
"source_file": "automation/data/sustainability_topics.json",
"compliance_score": null,
"ready_at": null,
"published_at": null,
"platform_urls": {}
} }
] ]
+95
View File
@@ -0,0 +1,95 @@
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from typing import List
from ..database import get_db
from ..models import Case
from ..schemas import CaseBase, CaseResponse
router = APIRouter(prefix="/api/admin/cases", tags=["admin"])
def get_current_admin(request: Request, db: Session = Depends(get_db)):
"""依赖项:验证管理员权限"""
from .auth import verify_token
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
raise HTTPException(status_code=401, detail="未提供认证令牌")
token = auth_header.split(" ")[1]
user = verify_token(token, db)
if user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return user
@router.get("", response_model=List[CaseResponse])
def list_cases(
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取案例列表(管理员)"""
cases = db.query(Case).all()
return [CaseResponse.from_orm(c) for c in cases]
@router.get("/{case_id}", response_model=CaseResponse)
def get_case(
case_id: int,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取单个案例详情"""
case = db.query(Case).filter(Case.id == case_id).first()
if not case:
raise HTTPException(status_code=404, detail="案例不存在")
return case
@router.post("", response_model=CaseResponse)
def create_case(
case_data: CaseBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""创建新案例"""
existing = db.query(Case).filter(Case.id == case_data.id).first()
if existing:
raise HTTPException(status_code=400, detail="案例ID已存在")
case = Case(**case_data.dict())
db.add(case)
db.commit()
db.refresh(case)
return case
@router.put("/{case_id}", response_model=CaseResponse)
def update_case(
case_id: int,
case_update: CaseBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""更新案例"""
case = db.query(Case).filter(Case.id == case_id).first()
if not case:
raise HTTPException(status_code=404, detail="案例不存在")
update_data = case_update.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(case, field, value)
db.commit()
db.refresh(case)
return case
@router.delete("/{case_id}")
def delete_case(
case_id: int,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""删除案例"""
case = db.query(Case).filter(Case.id == case_id).first()
if not case:
raise HTTPException(status_code=404, detail="案例不存在")
db.delete(case)
db.commit()
return {"message": "删除成功"}
+92
View File
@@ -0,0 +1,92 @@
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from typing import List
from ..database import get_db
from ..models import LLMConfig
from ..schemas import LLMConfigBase, LLMConfigResponse
router = APIRouter(prefix="/api/admin/llmconfigs", tags=["admin"])
def get_current_admin(request: Request, db: Session = Depends(get_db)):
"""依赖项:验证管理员权限"""
from .auth import verify_token
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
raise HTTPException(status_code=401, detail="未提供认证令牌")
token = auth_header.split(" ")[1]
user = verify_token(token, db)
if user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return user
@router.get("", response_model=List[LLMConfigResponse])
def list_llm_configs(
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取 LLM 配置列表"""
configs = db.query(LLMConfig).all()
return [LLMConfigResponse.from_orm(c) for c in configs]
@router.get("/{config_id}", response_model=LLMConfigResponse)
def get_llm_config(
config_id: int,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取单个 LLM 配置详情"""
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
return config
@router.post("", response_model=LLMConfigResponse)
def create_llm_config(
config_data: LLMConfigBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""创建 LLM 配置"""
config = LLMConfig(**config_data.dict())
db.add(config)
db.commit()
db.refresh(config)
return config
@router.put("/{config_id}", response_model=LLMConfigResponse)
def update_llm_config(
config_id: int,
config_update: LLMConfigBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""更新 LLM 配置"""
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
update_data = config_update.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(config, field, value)
db.commit()
db.refresh(config)
return config
@router.delete("/{config_id}")
def delete_llm_config(
config_id: int,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""删除 LLM 配置"""
config = db.query(LLMConfig).filter(LLMConfig.id == config_id).first()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
db.delete(config)
db.commit()
return {"message": "删除成功"}
+129
View File
@@ -0,0 +1,129 @@
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from typing import List, Dict, Any
from ..database import get_db
from ..models import SystemConfig
from ..schemas import SystemConfigBase, SystemConfigResponse
router = APIRouter(prefix="/api/admin/systemconfigs", tags=["admin"])
def get_current_admin(request: Request, db: Session = Depends(get_db)):
"""依赖项:验证管理员权限"""
from .auth import verify_token
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
raise HTTPException(status_code=401, detail="未提供认证令牌")
token = auth_header.split(" ")[1]
user = verify_token(token, db)
if user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return user
@router.get("", response_model=List[SystemConfigResponse])
def list_system_configs(
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取所有系统配置(键值对列表)"""
configs = db.query(SystemConfig).all()
# 将 value 解析为 JSON(如果是 JSON 字符串)
result = []
for c in configs:
resp = SystemConfigResponse.from_orm(c)
# 尝试解析 value 为 JSON
if c.value:
try:
import json
resp.value = json.loads(c.value)
except Exception:
pass # 保持原字符串
result.append(resp)
return result
@router.get("/{config_key}", response_model=SystemConfigResponse)
def get_system_config(
config_key: str,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取单个系统配置"""
config = db.query(SystemConfig).filter(SystemConfig.key == config_key).first()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
resp = SystemConfigResponse.from_orm(config)
if config.value:
try:
import json
resp.value = json.loads(config.value)
except Exception:
pass
return resp
@router.post("", response_model=SystemConfigResponse)
def create_system_config(
config_data: SystemConfigBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""创建或更新系统配置(UPSERT"""
# key 是主键,如果已存在则更新
existing = db.query(SystemConfig).filter(SystemConfig.key == config_data.key).first()
if existing:
# 若已存在,更新字段
if config_data.value is not None:
# 若 value 是 dict/list,转为 JSON 字符串存储
if isinstance(config_data.value, (dict, list)):
import json
existing.value = json.dumps(config_data.value, ensure_ascii=False)
else:
existing.value = str(config_data.value)
if config_data.description is not None:
existing.description = config_data.description
db.commit()
db.refresh(existing)
resp = SystemConfigResponse.from_orm(existing)
if existing.value:
try:
import json
resp.value = json.loads(existing.value)
except Exception:
pass
return resp
else:
# 新建
data = config_data.dict()
# 将 value 转为字符串(如果是复杂类型则 JSON)
if isinstance(data.get('value'), (dict, list)):
import json
data['value'] = json.dumps(data['value'], ensure_ascii=False)
config = SystemConfig(**data)
db.add(config)
db.commit()
db.refresh(config)
resp = SystemConfigResponse.from_orm(config)
if config.value:
try:
import json
resp.value = json.loads(config.value)
except Exception:
pass
return resp
@router.delete("/{config_key}")
def delete_system_config(
config_key: str,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""删除系统配置"""
config = db.query(SystemConfig).filter(SystemConfig.key == config_key).first()
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
db.delete(config)
db.commit()
return {"message": "删除成功"}
+102
View File
@@ -0,0 +1,102 @@
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from typing import List, Optional
from ..database import get_db
from ..models import TaskLog
from ..schemas import TaskLogBase, TaskLogResponse
router = APIRouter(prefix="/api/admin/tasklogs", tags=["admin"])
def get_current_admin(request: Request, db: Session = Depends(get_db)):
"""依赖项:验证管理员权限"""
from .auth import verify_token
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
raise HTTPException(status_code=401, detail="未提供认证令牌")
token = auth_header.split(" ")[1]
user = verify_token(token, db)
if user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return user
@router.get("", response_model=List[TaskLogResponse])
def list_task_logs(
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin),
topic_id: Optional[str] = None,
task_name: Optional[str] = None,
status: Optional[str] = None
):
"""获取任务日志列表(可过滤)"""
query = db.query(TaskLog)
if topic_id:
query = query.filter(TaskLog.topic_id == topic_id)
if task_name:
query = query.filter(TaskLog.task_name == task_name)
if status:
query = query.filter(TaskLog.status == status)
logs = query.order_by(TaskLog.started_at.desc()).all()
return [TaskLogResponse.from_orm(l) for l in logs]
@router.get("/{log_id}", response_model=TaskLogResponse)
def get_task_log(
log_id: int,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""获取单个任务日志详情"""
log = db.query(TaskLog).filter(TaskLog.id == log_id).first()
if not log:
raise HTTPException(status_code=404, detail="日志不存在")
return log
@router.post("", response_model=TaskLogResponse)
def create_task_log(
log_data: TaskLogBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""创建任务日志(用于手动记录)"""
log = TaskLog(**log_data.dict())
db.add(log)
db.commit()
db.refresh(log)
return log
@router.put("/{log_id}", response_model=TaskLogResponse)
def update_task_log(
log_id: int,
log_update: TaskLogBase,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""更新任务日志"""
log = db.query(TaskLog).filter(TaskLog.id == log_id).first()
if not log:
raise HTTPException(status_code=404, detail="日志不存在")
update_data = log_update.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(log, field, value)
db.commit()
db.refresh(log)
return log
@router.delete("/{log_id}")
def delete_task_log(
log_id: int,
request: Request,
db: Session = Depends(get_db),
admin_user = Depends(get_current_admin)
):
"""删除任务日志"""
log = db.query(TaskLog).filter(TaskLog.id == log_id).first()
if not log:
raise HTTPException(status_code=404, detail="日志不存在")
db.delete(log)
db.commit()
return {"message": "删除成功"}
+74 -2
View File
@@ -3,7 +3,7 @@ import os
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from .database import SessionLocal, init_db from .database import SessionLocal, init_db
from .models import Topic, User from .models import Topic, User, Case, LLMConfig, SystemConfig
import bcrypt import bcrypt
# 计算项目根目录(backend/app/initial_data.py -> 上升3层到 yu-zhi-ran # 计算项目根目录(backend/app/initial_data.py -> 上升3层到 yu-zhi-ran
@@ -11,6 +11,7 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
if os.getenv('PROJECT_ROOT'): if os.getenv('PROJECT_ROOT'):
PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT')) PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT'))
TOPICS_FILE = PROJECT_ROOT / "automation" / "data" / "sustainability_topics.json" TOPICS_FILE = PROJECT_ROOT / "automation" / "data" / "sustainability_topics.json"
CASES_FILE = PROJECT_ROOT / "automation" / "data" / "initial_cases.json"
# 从环境变量读取管理员配置 # 从环境变量读取管理员配置
DEFAULT_ADMIN_USERNAME = os.getenv('DEFAULT_ADMIN_USERNAME', 'admin') DEFAULT_ADMIN_USERNAME = os.getenv('DEFAULT_ADMIN_USERNAME', 'admin')
@@ -56,7 +57,78 @@ def import_initial_data():
else: else:
print("数据库已有选题数据,跳过导入") print("数据库已有选题数据,跳过导入")
# 2. 创建默认管理员用户(bcrypt 哈希)
# 3. 导入案例数据(如果为空)
if db.query(Case).count() == 0:
if __import__('os').path.exists(CASES_FILE):
cases_data = json.loads(open(CASES_FILE, encoding='utf-8').read())
for c in cases_data:
case = Case(
id=c['id'],
title=c['title'],
field=c['field'],
summary=c['summary'],
key_metrics=c.get('key_metrics'),
date=c.get('date'),
source=c['source'],
source_url=c.get('source_url'),
credibility_rating=c.get('credibility_rating'),
china_applicability=c.get('china_applicability')
)
db.add(case)
db.commit()
print(f"✅ 导入 {len(cases_data)} 条案例")
else:
print(f"⚠️ 案例文件不存在: {CASES_FILE}")
# 4. 插入 LLM 默认配置
if db.query(LLMConfig).count() == 0:
default_llm = LLMConfig(
name="default_expand",
system_prompt="你是一个专业的内容创作者。",
user_prompt_template="""你是一个专业的内容创作者,风格精炼、直接、切中要点。请将以下大纲扩展为完整的文章章节,要求如下:
### 选题信息
标题:{topic.get('title')}
领域:{topic.get('field')}
核心观点:{topic.get('core_concept', '')}
受众痛点:{topic.get('audience_pain', '')}
独特视角:{topic.get('unique_angle', '')}
### 当前章节
## {section_title}
{section_content}
### 输出要求
- 以 "## {section_title}" 开始
- 字数:200-300 字(精炼为主)
- 语言:直白、有冲击力,避免空洞套话
- 使用 Markdown 格式
- 每个论点配具体案例或数据支撑
- 确保与整体文章调性一致
直接输出完整 Markdown 章节(包括标题和正文)。""",
temperature=0.8,
max_tokens=1000,
model="stepfun-ai/step-3.5-flash",
is_active=True
)
db.add(default_llm)
db.commit()
print("✅ 插入默认 LLM 配置")
# 5. 插入系统配置默认值
default_system_configs = [
{"key": "collector_enabled", "value": "false", "description": "是否启用采集器"},
{"key": "scheduler_interval", "value": "daily", "description": "调度间隔:daily/hourly/weekly"},
]
for cfg in default_system_configs:
if db.query(SystemConfig).filter(SystemConfig.key == cfg["key"]).first() is None:
db.add(SystemConfig(**cfg))
db.commit()
print("✅ 插入默认系统配置")
# 2. 创建默认管理员用户(bcrypt 哈希)
admin_exists = db.query(User).filter(User.username == DEFAULT_ADMIN_USERNAME).first() admin_exists = db.query(User).filter(User.username == DEFAULT_ADMIN_USERNAME).first()
if not admin_exists: if not admin_exists:
hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt()) hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt())
+5 -1
View File
@@ -9,7 +9,7 @@ from pathlib import Path
from .database import engine, get_db, init_db from .database import engine, get_db, init_db
from .models import Base from .models import Base
from .api import topics, system, articles, publishing, auth, admin, audit, optimizer_logs from .api import topics, system, articles, publishing, auth, admin, audit, optimizer_logs, cases, task_logs, llm_configs, system_configs
from .initial_data import import_initial_data from .initial_data import import_initial_data
app = FastAPI(title="宇之然内容创作平台", version="0.1.0") app = FastAPI(title="宇之然内容创作平台", version="0.1.0")
@@ -38,6 +38,10 @@ app.include_router(auth.router)
app.include_router(admin.router) app.include_router(admin.router)
app.include_router(audit.router) app.include_router(audit.router)
app.include_router(optimizer_logs.router) app.include_router(optimizer_logs.router)
app.include_router(cases.router)
app.include_router(task_logs.router)
app.include_router(llm_configs.router)
app.include_router(system_configs.router)
# 挂载前端 # 挂载前端
FRONTEND_DIR = Path(__file__).parent.parent.parent / "frontend" FRONTEND_DIR = Path(__file__).parent.parent.parent / "frontend"
+66
View File
@@ -135,3 +135,69 @@ class AuditLogResponse(BaseModel):
model_config = ConfigDict(from_attributes=True) model_config = ConfigDict(from_attributes=True)
# --- 案例库 Schema ---
class CaseBase(BaseModel):
title: str
field: str
summary: str
key_metrics: Optional[str] = None
date: Optional[str] = None
source: str
source_url: Optional[str] = None
credibility_rating: Optional[str] = None
china_applicability: Optional[str] = None
class CaseResponse(CaseBase):
id: int
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
# --- 任务日志 Schema ---
class TaskLogBase(BaseModel):
task_name: str
topic_id: Optional[str] = None
status: str
message: Optional[str] = None
started_at: Optional[datetime] = None
finished_at: Optional[datetime] = None
duration_seconds: Optional[int] = None
class TaskLogResponse(TaskLogBase):
id: int
model_config = ConfigDict(from_attributes=True)
# --- LLM 配置 Schema ---
class LLMConfigBase(BaseModel):
name: str
system_prompt: Optional[str] = None
user_prompt_template: str
temperature: float = 0.7
max_tokens: int = 2000
model: Optional[str] = None
is_active: bool = True
class LLMConfigResponse(LLMConfigBase):
id: int
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
# --- 系统配置 Schema ---
class SystemConfigBase(BaseModel):
key: str
value: Optional[str] = None
description: Optional[str] = None
class SystemConfigResponse(SystemConfigBase):
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)