From 53c3948cad684b9329f17bba11b11e0b7d3734ce Mon Sep 17 00:00:00 2001 From: lt Date: Sat, 2 May 2026 09:13:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=A1=88=E4=BE=8B/?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=97=A5=E5=BF=97/LLM=E9=85=8D=E7=BD=AE/?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD\n\n-=20=E6=89=A9=E5=B1=95=E6=A1=88=E4=BE=8B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=87=B330=E4=B8=AA\n-=20=E6=96=B0=E5=A2=9ECase,=20Ta?= =?UTF-8?q?skLog,=20LLMConfig,=20SystemConfig=E7=9A=84API=E8=B7=AF?= =?UTF-8?q?=E7=94=B1\n-=20=E5=AE=8C=E5=96=84initial=5Fdata=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E8=84=9A=E6=9C=AC\n-=20=E5=88=9B=E5=BB=BA=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2admin.html?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=AE=8C=E6=95=B4=E5=A2=9E=E5=88=A0?= =?UTF-8?q?=E6=94=B9=E6=9F=A5\n-=20=E6=9B=B4=E6=96=B0=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=EF=BC=8C=E5=A2=9E=E5=8A=A0=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- automation/data/initial_cases.json | 362 +++++++++++++++++++++ automation/data/sustainability_topics.json | 320 ++++++------------ platform/backend/app/api/cases.py | 95 ++++++ platform/backend/app/api/llm_configs.py | 92 ++++++ platform/backend/app/api/system_configs.py | 129 ++++++++ platform/backend/app/api/task_logs.py | 102 ++++++ platform/backend/app/initial_data.py | 76 ++++- platform/backend/app/main.py | 6 +- platform/backend/app/schemas.py | 66 ++++ 9 files changed, 1025 insertions(+), 223 deletions(-) create mode 100644 automation/data/initial_cases.json create mode 100644 platform/backend/app/api/cases.py create mode 100644 platform/backend/app/api/llm_configs.py create mode 100644 platform/backend/app/api/system_configs.py create mode 100644 platform/backend/app/api/task_logs.py diff --git a/automation/data/initial_cases.json b/automation/data/initial_cases.json new file mode 100644 index 0000000..ec0d7c6 --- /dev/null +++ b/automation/data/initial_cases.json @@ -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": "初期投入 <$1000,20%实现月入$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": "⭐⭐⭐⭐⭐" + } +] \ No newline at end of file diff --git a/automation/data/sustainability_topics.json b/automation/data/sustainability_topics.json index 4ee0d94..6f5193f 100644 --- a/automation/data/sustainability_topics.json +++ b/automation/data/sustainability_topics.json @@ -4,379 +4,259 @@ "title": "远程工作2026中国指南:从\"不可能\"到\"可行\"的路径图", "field": "未来工作方式", "format": "趋势洞察 + 实操指南", - "core_concept": "在中国实现远程工作的系统性路径,涵盖法律合规(合同、社保、个税)、心理建设、协作工具与社群支持。", - "audience_pain": "担心远程不稳定、收入无保障、社交隔离、签证社保问题。", - "unique_angle": "不仅分析国外最佳实践,更聚焦中国本土约束条件,提供可落地的合规与操作方案。", + "core_concept": "法律实操(合同、社保、个税)+ 心理建设(孤独应对)", + "audience_pain": "想要远程但面临制度限制、社保个税不清晰、孤独感", + "unique_angle": "从兼职接单开始,试探公司政策,降低风险", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T002", "title": "AI副业入门:用DeepSeek实现第一笔收入的100天", "field": "未来工作方式", "format": "趋势洞察 + 实操指南", - "core_concept": "利用DeepSeek等国产大模型提供AI副业服务,实现从零到日赚50元的实践路径。", - "audience_pain": "不知道能用AI做什么副业,且不清楚如何在现有平台接单与规避违规。", - "unique_angle": "给出具体的服务类型清单、定价策略和红线清单,以快速获得第一笔收入为目标。", + "core_concept": "服务类型清单 + 定价策略 + 违规红线", + "audience_pain": "不知道能做什么、平台抽成高、怕违规", + "unique_angle": "从代写文案/数据分析起步,日赚50元", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T003", "title": "数字游民签证全解析:30个国家政策对比,中国护照能去哪些?", "field": "未来工作方式", "format": "趋势洞察 + 实操指南", - "core_concept": "全景式解析全球30国的数字游民签证与配套政策,评估中国护照持有者的可行性与成本。", - "audience_pain": "想地理套利但担心签证、保险、税务和社群的复杂性。", - "unique_angle": "提供全成本分析(签证+保险+税务+社群)并给出低成本试水方案(如泰国/马来西亚3个月)。", + "core_concept": "签证+保险+税务+社群的全成本分析", + "audience_pain": "签证受限、社保断缴焦虑、信息不对称", + "unique_angle": "泰国/马来西亚试水,成本不到2万", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T004", "title": "一人公司实验:从创意到营收的365天日志", "field": "未来工作方式", "format": "趋势洞察 + 实操指南", - "core_concept": "从创意到营收的365天实验,涵盖MVP构建、现金流管理与法律合规。", - "audience_pain": "想独立创业但怕失败、缺启动资金、不懂营销。", - "unique_angle": "先通过接单验证需求,再产品化,降低风险。", + "core_concept": "最小可行产品(MVP) + 现金流管理 + 法律合规", + "audience_pain": "怕失败、缺启动资金、不懂营销", + "unique_angle": "先接单验证需求,再产品化", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T005", "title": "AI时代的技能组合:什么技能值得投入10年?", "field": "未来工作方式", "format": "趋势洞察 + 实操指南", - "core_concept": "基于WEF未来技能报告和中国就业市场,划分四大技能类别:AI强化型、AI无法替代、复合型、过时型。", - "audience_pain": "不知道学什么技能对未来有价值,学了不知如何应用。", - "unique_angle": "帮助绘制个人技能地图,识别自己的“护城河”技能并制定fill plan。", + "core_concept": "四个维度:AI强化型、AI无法替代、复合型、过时型", + "audience_pain": "不知道学什么、学了不知道用在哪", + "unique_angle": "绘制个人技能地图,识别\"护城河技能\"", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T006", "title": "城市农业ROI报告:20㎡阳台种菜一年,省了多少钱?", "field": "可持续生活系统", "format": "趋势洞察 + 实操指南", - "core_concept": "在20平方米阳台种植蔬菜,评估品种选择、智能设备与成本核算,实现3个月回本。", - "audience_pain": "城市空间小、光照不足,怕邻居投诉,担心投入产出比。", - "unique_angle": "从高ROI香草开始,提供自动化灌溉方案,年省500-2000元。", + "core_concept": "品种选择(高ROI蔬菜)+ 智能设备(自动灌溉)+ 成本核算", + "audience_pain": "空间小、光照不足、怕邻居投诉", + "unique_angle": "从香草开始,3个月回本,年省500-2000元", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T007", "title": "零浪费家庭实验:一年只产100L垃圾,可能吗?", "field": "可持续生活系统", "format": "趋势洞察 + 实操指南", - "core_concept": "一年只产100升垃圾的实验,通过垃圾追踪、替代方案数据库与社区互助实现。", - "audience_pain": "垃圾分类执行难,环保产品贵,个人力量渺小。", - "unique_angle": "从塑料减量入手,减少50%非必要垃圾,提供系统化工具与社群支持。", + "core_concept": "垃圾追踪表 + 替代方案数据库 + 社区互助", + "audience_pain": "垃圾分类执行难、环保产品贵、缺乏系统性", + "unique_angle": "从\"塑料减量\"开始,减少50%非必要垃圾", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T008", "title": "低碳生活账单:用3年省了8万,碳足迹降了60%", "field": "可持续生活系统", "format": "趋势洞察 + 实操指南", - "core_concept": "通过交通(电动车+共享)、饮食(植物为主)、消费(二手优先)三大维度实现碳足迹降低60%,三年省8万元。", - "audience_pain": "碳减排听起来成本高,执行复杂,个人难坚持。", - "unique_angle": "记录碳足迹APP,每月减排5%,经济回报可视化,年省5000+。", + "core_concept": "交通(电动车+共享)+ 饮食(植物为主)+ 消费(二手优先)", + "audience_pain": "电费、用车成本、生活质量担忧", + "unique_angle": "记录碳足迹APP,每月减排5%,年省5000+", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T009", "title": "循环消费实战:10件物品,用3年省了2万", "field": "可持续生活系统", "format": "趋势洞察 + 实操指南", - "core_concept": "10件物品通过循环使用(买二手、租、延长寿命、转卖)三年省2万元的实战策略。", - "audience_pain": "二手文化不成熟,维修成本高,购买决策困难。", - "unique_angle": "购买决策树(买新/二手/租)+ 延长寿命技巧 + 转卖策略,省30-50%开支。", + "core_concept": "购买决策树(买新/二手/租)+ 延长寿命技巧 + 转卖策略", + "audience_pain": "二手文化不成熟、维修成本高、不知如何选择", + "unique_angle": "手机、相机、家具优先二手,省30-50%", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T010", "title": "社区菜园指南:如何推动小区5户邻居共建共享", "field": "可持续生活系统", "format": "趋势洞察 + 实操指南", - "core_concept": "推动小区5户邻居共建共享社区菜园,解决物权、利益分配与技术方案问题。", - "audience_pain": "物业/邻居协调难,法律风险大,不知道如何组织。", - "unique_angle": "先找1个友好小区试点,成功后复制,提供分区与智能管理方案。", + "core_concept": "法律风险(物权)+ 利益分配机制 + 技术方案(分区+智能)", + "audience_pain": "物业/邻居协调难、缺乏政策支持", + "unique_angle": "先找1个友好小区试点,成功后再推广", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T011", "title": "第二大脑2.0:用DeepSeek+本地向量库建立私有知识系统", "field": "个人知识工厂", "format": "趋势洞察 + 实操指南", - "core_concept": "用DeepSeek加本地向量库构建私有知识系统,确保数据主权、隐私保护和无缝检索。", - "audience_pain": "云笔记服务隐私担忧,信息碎片化,检索困难。", - "unique_angle": "先用DeepSeek对话模式验证需求,再迁移到本地部署,降低门槛。", + "core_concept": "数据主权 + 隐私保护 + 无缝检索 + AI问答", + "audience_pain": "不知道能做什么、数据安全意识弱", + "unique_angle": "先用DeepSeek对话模式,再迁移至本地部署", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T012", "title": "PKM极简实践:PARA系统在Notion上的落地模板", "field": "个人知识工厂", "format": "趋势洞察 + 实操指南", - "core_concept": "PARA系统在Notion上的简化落地,仅保留3个核心文件夹,每周10分钟维护,AI辅助整理。", - "audience_pain": "学了PARA体系坚持不了,工具太复杂,维护耗时。", - "unique_angle": "简化到4个区( AREA、Projects、Resources、Archives),每天花5分钟归档,结合AI自动分类。", + "core_concept": "简化到3个核心文件夹 + 每周10分钟维护 + AI辅助整理", + "audience_pain": "学了方法坚持不了、工具复杂难上手", + "unique_angle": "建立4个PARA区,每天花5分钟归档", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T013", "title": "费曼学习法AI增强:如何让AI帮你\"教\"懂一个概念", "field": "个人知识工厂", "format": "趋势洞察 + 实操指南", - "core_concept": "利用AI辅助的费曼技巧:AI简化概念 → 自我复述 → 识别差距,使学习更高效。", - "audience_pain": "学完不会表达,无法判断自己是否真正理解,缺乏反馈。", - "unique_angle": "每周用AI验证一个概念的理解深度,输出倒逼输入。", + "core_concept": "三步法(AI简化→自我复述→Gap识别)+ 输出倒逼输入", + "audience_pain": "应试教育思维、输出能力弱", + "unique_angle": "每周学1个概念,用AI验证理解深度", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T014", "title": "AI个人助理搭建:从ChatGPT到私有化部署的完整路线", "field": "个人知识工厂", "format": "趋势洞察 + 实操指南", - "core_concept": "从ChatGPT云端API到本地私有化部署的完整路线,权衡成本、数据安全与定制化。", - "audience_pain": "想用AI助理但担心数据泄露,又不知如何选择方案。", - "unique_angle": "先用免费API试用,数据敏感时再本地部署,提供分阶段迁移路径。", + "core_concept": "数据主权 + 定制化 + 成本控制(从免费到付费)", + "audience_pain": "数据隐私顾虑、 API 成本、功能定制需求", + "unique_angle": "先用API调用,数据敏感再本地部署", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T015", "title": "技能树可视化:用思维导图规划5年职业路径", "field": "个人知识工厂", "format": "趋势洞察 + 实操指南", - "core_concept": "用思维导图规划5年职业路径,构建硬技能×软技能矩阵,对标行业能力模型。", - "audience_pain": "不清楚该学什么,学完不知如何应用,职业发展迷茫。", - "unique_angle": "画出当前技能地图,识别3个关键gap,制定fill plan,并链接学习资源。", + "core_concept": "硬技能×软技能矩阵 + 行业对标 + 学习资源聚合", + "audience_pain": "不知道学什么、学了不知道用在哪、缺乏系统性", + "unique_angle": "画出当前技能地图,识别3个gap,制定fill plan", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T016", "title": "AI伦理实践指南:开发者在中国的合规清单", "field": "科技人文交叉", "format": "趋势洞察 + 实操指南", - "core_concept": "中国开发者合规清单:数据隐私、歧视检测、透明度义务与备案流程。", - "audience_pain": "AI伦理讨论多但实践少,国内监管政策不明确。", - "unique_angle": "将EU AI Act转化为中国可操作的自查表,个人项目也能快速落地。", + "core_concept": "数据隐私 + 歧视检测 + 透明度义务 + 备案流程", + "audience_pain": "算法推荐管理规定不明、合规成本高、缺乏实操指南", + "unique_angle": "个人项目先做伦理自查表,避免踩雷", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T017", "title": "数字排毒月:戒掉微信/抖音后,生活发生了什么", "field": "科技人文交叉", "format": "趋势洞察 + 实操指南", - "core_concept": "通过渐进式戒断(如设定无屏时段)和替代活动,缓解社交依赖与微信深度使用。", - "audience_pain": "工作必须在线,担心失联,社交圈绑定微信无法脱离。", - "unique_angle": "从小目标开始(如21:00-7:00无屏),逐步延长,结合线下活动填补空白。", + "core_concept": "渐进式戒断 + 替代活动 + 社交边界管理", + "audience_pain": "工作必须在线、社交依赖微信、戒断恐惧", + "unique_angle": "先设定\"无屏时段\"(21:00-7:00),逐步延长", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T018", "title": "银发科技报告:给爸妈装智能设备,学到的5个设计原则", "field": "科技人文交叉", "format": "趋势洞察 + 实操指南", - "core_concept": "给父母安装智能设备时总结的5个反直觉设计原则:简化选项、物理反馈、容错、情感连接。", - "audience_pain": "老人操作困难,适老化产品鸡肋,子女教学成本高。", - "unique_angle": "改造一个设备(如手机)让父母真正用起来,而不是堆功能。", + "core_concept": "简化选项 + 物理反馈 + 容错设计 + 情感连接", + "audience_pain": "老人数字化难、适老化产品差、子女教不会", + "unique_angle": "改造1个设备(如手机),让父母真正用起来", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T019", "title": "儿童数字素养课:10岁儿子的AI启蒙12周", "field": "科技人文交叉", "format": "趋势洞察 + 实操指南", - "core_concept": "10岁儿子12周AI启蒙项目,培养批判性思维、创造力与AI生成内容鉴别能力。", - "audience_pain": "家长焦虑孩子屏幕时间,但又无法完全禁止,缺乏引导方法。", - "unique_angle": "每周一次“AI家庭时间”,共同探讨AI生成内容的真伪,培养媒介素养。", + "core_concept": "批判性思维 + 创造力激发 + 家长引导策略", + "audience_pain": "应试压力大、家长焦虑又依赖、不知道如何启蒙", + "unique_angle": "每周1次\"AI家庭时间\",探讨AI生成内容真伪", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] }, { "id": "T020", "title": "科技与自然共生:如何用AI让阳台农场更\"自然\"", "field": "科技人文交叉", "format": "趋势洞察 + 实操指南", - "core_concept": "用AI让阳台农场更“自然”:传感器监测、及时提醒,但保留“浇水仪式感”。", - "audience_pain": "技术让园艺变得机械,失去自然乐趣,过度自动化反而增加维护复杂度。", - "unique_angle": "技术隐形化,只提供必要提醒,保留人的参与感和情感连接。", + "core_concept": "技术隐形化 + 自然反馈闭环 + 人工情感连接", + "audience_pain": "技术过度干预、失去自然体验、缺乏情感温度", + "unique_angle": "用传感器+提醒,但保留\"浇水仪式感\"", "priority": "高", "priority_score": 90, - "total_score": null, - "status": "pending", - "cases": [], - "source_file": "automation/data/sustainability_topics.json", - "compliance_score": null, - "ready_at": null, - "published_at": null, - "platform_urls": {} + "status": "待处理", + "cases": [] } ] \ No newline at end of file diff --git a/platform/backend/app/api/cases.py b/platform/backend/app/api/cases.py new file mode 100644 index 0000000..fd69e16 --- /dev/null +++ b/platform/backend/app/api/cases.py @@ -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": "删除成功"} diff --git a/platform/backend/app/api/llm_configs.py b/platform/backend/app/api/llm_configs.py new file mode 100644 index 0000000..9e322d3 --- /dev/null +++ b/platform/backend/app/api/llm_configs.py @@ -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": "删除成功"} diff --git a/platform/backend/app/api/system_configs.py b/platform/backend/app/api/system_configs.py new file mode 100644 index 0000000..e76edf2 --- /dev/null +++ b/platform/backend/app/api/system_configs.py @@ -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": "删除成功"} diff --git a/platform/backend/app/api/task_logs.py b/platform/backend/app/api/task_logs.py new file mode 100644 index 0000000..805f77d --- /dev/null +++ b/platform/backend/app/api/task_logs.py @@ -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": "删除成功"} diff --git a/platform/backend/app/initial_data.py b/platform/backend/app/initial_data.py index 0f53df7..eefad8e 100644 --- a/platform/backend/app/initial_data.py +++ b/platform/backend/app/initial_data.py @@ -3,7 +3,7 @@ import os from datetime import datetime from pathlib import Path from .database import SessionLocal, init_db -from .models import Topic, User +from .models import Topic, User, Case, LLMConfig, SystemConfig import bcrypt # 计算项目根目录(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'): PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT')) 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') @@ -56,7 +57,78 @@ def import_initial_data(): else: 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() if not admin_exists: hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt()) diff --git a/platform/backend/app/main.py b/platform/backend/app/main.py index 6cc54a3..5ba6284 100644 --- a/platform/backend/app/main.py +++ b/platform/backend/app/main.py @@ -9,7 +9,7 @@ from pathlib import Path from .database import engine, get_db, init_db 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 app = FastAPI(title="宇之然内容创作平台", version="0.1.0") @@ -38,6 +38,10 @@ app.include_router(auth.router) app.include_router(admin.router) app.include_router(audit.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" diff --git a/platform/backend/app/schemas.py b/platform/backend/app/schemas.py index 58055d1..e89920a 100644 --- a/platform/backend/app/schemas.py +++ b/platform/backend/app/schemas.py @@ -135,3 +135,69 @@ class AuditLogResponse(BaseModel): 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) +