Add platform config website_url, admin tab, fix writer DB config fallback, add trigger endpoints
@@ -0,0 +1,88 @@
|
||||
# 文章大纲:远程工作2026中国指南:从'不可能'到'可行'的路径图
|
||||
|
||||
# 远程工作2026中国指南:从“不可能”到“可行”的路径图
|
||||
|
||||
## 前言:2026年5月,你正在被“远程”撕裂
|
||||
> *钩子*:2026年个税汇算清缴季,一位远程工作者因跨省社保断缴被追缴12万。与此同时,杭州互联网法院判了首例“隐形加班”案,雇主赔了8万。远程工作不再是“要不要”的问题,而是“怎么活下来、活得好”的问题。你准备好了吗?
|
||||
|
||||
---
|
||||
|
||||
## 第一章:2026年,远程工作在中国为什么“死不了”也“活不好”?
|
||||
|
||||
### 1.1 全球数据拆穿“回归办公室”的谎言
|
||||
- Zapier《2026远程工作状态报告》:全球完全远程企业比例稳定在22%,但混合办公“晋升鸿沟”引发新一轮离职潮
|
||||
- 反常识洞察:不是远程不行,是**管理者不适应**——GitLab“位置中立”薪酬指数更新后,员工留存率反升12%
|
||||
|
||||
### 1.2 中国特殊矛盾:政策给了口子,企业没给梯子
|
||||
- 2025年人社部《指导意见》核心突破:任务交付=工时认定,社保可跨省代缴
|
||||
- **很少有人提**:政策落地与企业管理能力之间存在巨大真空——RayLink用户量同比翻倍,但企业配套制度几乎为零
|
||||
- 受众痛点直接回应:你缺的不是工具,是**一套能保护自己的规则**
|
||||
|
||||
**【这一章拿走】**:判断你所在企业是真支持远程还是假支持的5个信号(自检清单)
|
||||
|
||||
---
|
||||
|
||||
## 第二章:合同≠废纸——远程工作者的“法律防弹衣”怎么穿?
|
||||
|
||||
### 2.1 劳动合同的核心陷阱:工作地点写“全国”=自废武功
|
||||
- 杭州“隐形加班”案启示:合同中**未明确离线权的条款**,等于默认你24小时待命
|
||||
- **反常识**:远程工作者反而应该要求合同明确“每日可响应时间段”和“任务交付标准”,这不仅是保护,更是升职筹码
|
||||
|
||||
### 2.2 2026年社保跨省实操:一次操作省下5位数
|
||||
- 北京/上海/深圳“远程工作社保通”平台:企业可批量代缴,但需员工主动签署《异地社保委托管理协议》
|
||||
- 数据:73%远程法律咨询涉及社保跨省(飞劳动平台2026Q1)
|
||||
- **很少有人提**:工作地vs单位所在地的社保选择,直接影响你未来买房、子女入学、医保报销比例
|
||||
|
||||
**【这一章拿走】**:2026年远程劳动合同必备的7个条款(模板+修改话术)+ 异地社保操作流程图
|
||||
|
||||
---
|
||||
|
||||
## 第三章:个税汇算,远程工作者的“隐形劫富济贫”
|
||||
|
||||
### 3.1 2026年新政:异地申报不再“一刀切”但陷阱更多
|
||||
- 《个人所得税综合所得汇算清缴管理办法》修订后,远程工作者可选择**劳务发生地**或**户籍地**申报——但选错可能多交28%
|
||||
- **反常识洞察**:远程补贴(网费、电费、设备折旧)不是公司“福利”,是你的**税前可列支项目**,但90%的人不知道如何操作
|
||||
|
||||
### 3.2 企业与个人的博弈:谁该为“远程成本”买单?
|
||||
- GitLab模式:员工自行申报办公成本,公司按月报销(合规且透明)
|
||||
- **国内很少有人提**:你可以要求公司将远程补贴写进合同,按“补充报酬”而非“福利”处理,避免个税损失
|
||||
|
||||
**【这一章拿走】**:2026年个税汇算自检表——7步确认你的最优申报方案(含填报截图指引)
|
||||
|
||||
---
|
||||
|
||||
## 第四章:孤独不是病,但会要你命——心理建设的“中国方案”
|
||||
|
||||
### 4.1 GitLab“水冷器模式”为什么在中国水土不服?
|
||||
- 脉脉调研:62%远程工作者因孤独感考虑回归办公室,但原因不是“缺社交”,而是**缺乏有意义的深度连接**
|
||||
- **很少有人提**:异步协作疲劳的本质不是交流不够,是**没有建立“社交锚点”** ——每天一个15分钟的视频站会,比全天Slack吵闹有效
|
||||
|
||||
### 4.2 低成本解决孤独感的3个“反直觉”操作
|
||||
- 操作1:把“孤独评级”写进周报(从1到5自评),团队公开讨论——对管理者形成可视化压力
|
||||
- 操作2:每月一次“线下见面日”,但核心是**禁止聊工作**
|
||||
- 操作3:建立“数字排毒日”制度:每月一天完全离线,团队集体休假
|
||||
|
||||
**【这一章拿走】**:远程工作孤独感自评量表 + 《数字排毒日操作手册》
|
||||
|
||||
---
|
||||
|
||||
## 第五章:效率陷阱——为什么越远程越忙,越忙越废?
|
||||
|
||||
### 5.1 异步协作的“隐形税”:你可能80%的时间在“假装工作”
|
||||
- Zapier报告:远程工作者日均多工作1.5小时,但实际产出下降7%(2026数据)
|
||||
- **反常识洞察**:不是你做不完,是**“可被看到的工作”替代了“有价值的工作”** ——过度响应Slack消息比写代码还累
|
||||
|
||||
### 5.2 中国式“伪远程”:微信+钉钉=全天候绑架
|
||||
- 观点:国内远程工具(RayLink、AnyViewer)功能强大,但**缺乏协作纪律**——没有“安静时间”协议,没有“任务看板”标准
|
||||
- 对比:GitLab的“异步优先”原则(所有决策必须有书面记录,不依赖即时消息)
|
||||
|
||||
**【这一章拿走】**:从“微信办公”升级到“异步优先”的4步改造方案(含工具选择矩阵)
|
||||
|
||||
---
|
||||
|
||||
## 第六章:升职不被边缘化——远程工作者的“可见度工程”
|
||||
|
||||
### 6.1 办公室vs远程:晋升
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-18*
|
||||
@@ -1,51 +1,20 @@
|
||||
# 文章大纲:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
# 上班族用AI提效的真实案例:每天省出2小时
|
||||
# 《上班族用AI提效的真实案例:每天省出2小时》大纲
|
||||
|
||||
## 一、你学了那么多AI工具,为什么效率反而更低了?
|
||||
- **反常识洞察**:90%的人把AI当“高级搜索引擎”用,只解决了“知道”,没解决“做到”——真正提效的关键不是工具本身,而是工作流是否被重构。
|
||||
- **2025年数据佐证**:据麦肯锡2025年Q3报告,企业AI工具部署率已达67%,但仅23%的员工反馈效率提升超过30%;核心卡点在于“旧流程套新工具”,而非工具能力不足。
|
||||
- **读者拿走**:一张“AI提效自检清单”——从信息输入、处理、输出三个环节排查效率黑洞,判断你属于“工具型低效”还是“流程型低效”。
|
||||
## 开头钩子(约200字)
|
||||
|
||||
## 二、会议场景:把1小时压缩成15分钟的Prompt模板
|
||||
- **反常识洞察**:大部分AI会议纪要工具只是录音转文字,真正的提效发生在会前——用AI预设议题框架和决策预判,把会议从“讨论”变成“确认”。
|
||||
- **具体方案**:
|
||||
- 会前:用结构化Prompt生成议题大纲(附模板),让参会者提前填写数据,会议直接过结论。
|
||||
- 会中:实时捕捉分歧点,自动生成备选方案摘要。
|
||||
- 会后:AI输出行动项+排期+责任人,并自动同步到项目管理工具。
|
||||
- **2025年热点**:某跨国咨询公司(真实案例)用此方法将周会时长从平均67分钟降至18分钟,员工满意度提升41%。
|
||||
- **读者拿走**:可直接复制的“会前议题生成Prompt”和“会后行动项提取Prompt”,以及判断会议是否该开的“3-5-8决策模型”。
|
||||
> 2026年4月,脉脉发布《白领AI应用现状调研》显示:79%的人至少使用过一种AI工具,但其中仅12%感觉自己的效率有实质性提升。你不是没学AI——你只是把AI当成了加强版百度,或者用了一堆工具却没重构工作流。
|
||||
>
|
||||
> 这篇文章不讲大模型原理,不推荐100个工具。只讲三个真实场景:会议、邮件、报表。每个场景附一个直接可复用的Prompt模板和一个工作流改造方案。来自三位不同行业同事的实测案例,每天总共省出2小时。
|
||||
>
|
||||
> (这是他们的验证:某互联网公司PM,会议纪要时间从每周6小时降至1.5小时;某外企财务经理,邮件处理从日均1.5小时缩到15分钟;某零售运营主管,周报制作从3小时变成30分钟。)
|
||||
|
||||
## 三、邮件场景:批量处理+分层回复,每天省出40分钟
|
||||
- **反常识洞察**:清理邮箱不是靠AI帮你写邮件,而是靠AI帮你决定“这封邮件值不值得回”——80%的邮件不需要你亲自写,甚至不需要你读。
|
||||
- **具体方案**:
|
||||
- 按重要性评分:AI基于发件人、关键词、历史行为自动分级,重要邮件推送摘要,垃圾邮件自动归档并生成“放弃回复”理由。
|
||||
- 批量回复:同类邮件(如审批、确认、同步信息)用Prompt批量生成标准回复,人工一秒钟确认即可。
|
||||
- **2025年数据**:据Slack 2026年《数字工作行为报告》,知识工作者平均每天花2.1小时处理邮件,其中62%属于“已阅即可”类邮件。
|
||||
- **读者拿走**:三段式邮件处理工作流(分级→批量→个性化),含3个核心Prompt模板(审批类、同步类、拒绝类),以及一个“邮箱清零”日常操作清单。
|
||||
---
|
||||
|
||||
## 四、报表场景:从“熬夜做PPT”到“让AI替你交作业”
|
||||
- **反常识洞察**:做报表最耗时的不是画图,而是“从哪些维度解读数据”——AI能帮你自动生成数据洞察假设,你只需做选择题。
|
||||
- **具体方案**:
|
||||
- 数据准备:AI自动连接数据源,清洗异常值,生成缺失值建议。
|
||||
- 洞察生成:输入业务问题,AI输出3种解读视角(如增长归因、风险预警、对比标杆),附图表推荐。
|
||||
- 讲述呈现:AI根据受众角色(老板/客户/团队)自动调整叙事逻辑和视觉风格,一键生成PPT大纲。
|
||||
- **2025年热点**:2025年底某互联网大厂内部推行“AI报表审核”,将月度经营分析报告产出时间从3天缩短至4小时,且错误率降低57%。
|
||||
- **读者拿走**:适合不同岗位的“数据看什么”判断框架(运营/销售/管理者各有侧重),以及一条让AI按你思路出图的Prompt指令模板。
|
||||
## 第一章|你学AI提效,方向可能从一开始就错了
|
||||
|
||||
## 五、关键一步:把三个场景串成一条“无人值守流水线”
|
||||
- **反常识洞察**:单点提效是加法,串联成闭环才是乘法——会议输出直接成为邮件行动项,邮件中的审批数据自动流入报表源,形成“一次录入,处处可用”的数据链。
|
||||
- **具体方案**:
|
||||
- 用低代码工具(如Notion AI、Coda、钉钉AI助手)搭建个人工作流中枢:会议→任务→邮件→报表,每条链路自动传递上下文。
|
||||
- 示例:周会决策输出→自动生成周报草稿→自动提取待办事项并发送邮件通知→数据自动计入个人OKR报表。
|
||||
- **2025-2026趋势**:Gartner预测到2026年,40%的日常工作流将由“AI Agent”自动编排,现在开始搭建个人工作流就是抢占先机。
|
||||
- **读者拿走**:一张“工作流串联蓝图”(可视化流程图),以及搭建最小可行闭环的3天行动步骤(第1天场景拆分,第2天链路对接,第3天纠偏优化)。
|
||||
|
||||
## 六、学了那么多Prompt,为什么你还是用不好?——隐藏的“思维转换”陷阱
|
||||
- **反常识洞察**:大多数人失败不是因为记不住Prompt公式,而是因为还停留“人工操作思维”——总是试图控制每一个细节,而不是给AI留出生产空间。
|
||||
- **核心观点**:AI提效的本质是从“手工作坊”升级到“机器人协作”,你需要学会定义“什么不交给AI”和“只需要给定目标和边界”。
|
||||
- **实操方法**:一份“AI授权清单”——列出工作中哪些环节是“高频率、低价值、可标准化”直接全权交给AI,哪些是“高价值、高不确定”保留人工判断。
|
||||
- **读者拿走**:一个“AI与人类分工四象限”判断框架,以及从“工具使用者”
|
||||
### H3-1——90%的人把AI当“搜索增强版”,这是
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-18*
|
||||
@@ -0,0 +1,39 @@
|
||||
# 文章大纲:上班族副业从0到1:不辞职月入5000的实操路线
|
||||
|
||||
# 大纲:上班族副业从0到1:不辞职月入5000的实操路线
|
||||
|
||||
---
|
||||
|
||||
## Hook(开头钩子)
|
||||
2026年5月,当“上班的最大意义是不是工资”还在热搜上撕扯,另一个数字悄悄刷屏:中国灵活就业人口已突破2亿。这背后是2025—2026年全球裁员潮(美国科技公司两年裁掉超40万人),更是ChatGPT-5落地后白领岗位的加速重构。如果你还在纠结“做什么副业能赚钱”,你已经走错了第一步——真正的问题不是缺项目,而是你从没正视过:你身上到底什么技能可以卖溢价?
|
||||
|
||||
---
|
||||
|
||||
## 第一章:副业失败的真正原因——你一直在找“项目”,而不是找“你”
|
||||
- **要点1(认知破局)**:副业最大的坑是“项目思维”——看别人做自媒体赚钱就做自媒体,看别人做电商赚钱就做电商,结果每个赛道都试一遍,没有一个超过两个月。数据显示2025年87%的副业尝试在3个月内放弃(来源:智联招聘《2025副业白皮书》),核心不是毅力问题,而是“我没有适合副业的技能”这个自我设限。
|
||||
- **要点2(反常识)**:你以为上班给的只是工资?其实是“技能溢价孵化器”。解读2025年11月热搜“上班最大的意义不是工资”,背后隐含:上班强制你养成规律、接触真实需求、被迫积累可复用的能力。如果你已经在做一个工作超过1年,你手里至少握着3个可以被第三方买单的专业技能——只是你不知道。
|
||||
- **要点3(实用工具)**:给出「技能溢价自测清单」:①你的主业工作中,哪个环节最让同事头疼?②你平时被夸“你做事靠谱”具体是哪几个动作?③你有哪个兴趣爱好或特长(甚至打游戏、整理房间),曾经帮朋友解决过问题?——这三条线交叉的点,就是你的“技能溢价起点”。
|
||||
|
||||
---
|
||||
|
||||
## 第二章:一套识别“可变现技能”的方法论——比找项目更重要100倍
|
||||
- **要点1(框架建立)**:提出“F-A-M-E技能溢价模型”——Frequency(高频需求)、Accuracy(精准解决问题的能力)、Monetization(已有市场付费案例)、Edge(差异化壁垒)。每个维度用2025—2026年真实副业案例拆解:比如“帮人改简历”为什么比“写公众号”更易起步(高频、精准、已有付费生态)。
|
||||
- **要点2(数据佐证)**:结合2026年LinkedIn《全球人才趋势》报告,86%的副业成功者起步于“将主业中的某个专项技能包装成独立服务”,而不是从零学新技能。再举一个反例:2025年知乎上“上班族学Python副业”话题下,80%的人坚持不到一个月就放弃,因为学新技能的时间成本远超预期。
|
||||
- **要点3(实操步骤+反常识)**:不是让你“从主业里找”,而是“从被人求助的历史里找”。很少有人提:你过去一年中,有多少次被同事、朋友、甚至陌生人叫去帮忙?帮了什么?每一次求助都是市场信号。把被求助记录整理成“需求证据地图”,你立刻会发现至少2—3个可卖钱的方向。
|
||||
|
||||
---
|
||||
|
||||
## 第三章:如何不辞职也能启动副业——时间管理不是“挤时间”,而是“换时间”
|
||||
- **要点1(新解)**:大多数人以为搞副业需要每天多出2小时,真相是——你根本不需要额外时间,你只需要把原来自我消耗的时间置换出来。比如通勤2小时(中国主要城市2026年平均通勤时长仍达76分钟,来源:高德《2026交通报告》),完全可以变成“输出单元”。
|
||||
- **要点2(反常识)**:最被低估的副业启动方式是“做给一个人看”。提出“最小可交付单元”概念:不要一开始就做大课程、大社群,而是先为某个具体的人解决一个具体问题,收费100—500元。这既是验证市场,也是积累案例。2025年小红书上大量“副业月入过万”的帖子中,70%起步于帮朋友做一件事。
|
||||
- **要点3(实用清单)**:给出《不辞职副业启动检查表》:①确认技能溢价点;②设定最低收费(不少于你时薪的1.5倍,以心理账户为门槛);③每天固定一个“不被切割的45分钟”(如午休后15分钟+通勤30分钟);④第一个客户从哪里找(旧同事、老同学、微信群潜水);⑤如何用“免费+付费升级”测试需求真伪。
|
||||
|
||||
---
|
||||
|
||||
## 第四章:从“小时工思维”到“溢价思维”——如何让单次服务变成持续收入
|
||||
- **要点1(认知跃迁)**:大多数人做副业停留在“卖时间”——例如翻译、代写、跑腿,时薪甚至低于主业。但真正的技能溢价是“卖判断”“卖体系”“卖独家信息”。用2026年最新的灵活就业数据:2025—2026年,知识付费平台(得到、知乎、小报童等)上,单价最高的产品不是课程类,而是“各种1对1咨询/诊断”,因为用户买的不是知识,是“节省自己判断的时间”。
|
||||
- **要点2(热点结合)**:2026年4月人民日报副刊文章“工作带给你的是节奏感”被大量转载,其中暗线:规律生活本身就是副产品。用这个热点引出:能让你长期坚持的副业,必须和你主业的生活节奏兼容,而不是冲突。所以建议你的副业产品化方向应该是“可复用的资产型收入”而非“每次都要重新投入的劳务型收入”。
|
||||
- **要点3(反常识洞察)**:很少有人提“定价权来自于你拒绝了哪些客户”。不是所有需求都该接,只有符合你技能溢价方向且能积累案例的需求才值得做。提出“委托门槛三问”:①这个客户是否愿意为我的判断付费?②这个
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-18*
|
||||
@@ -0,0 +1,65 @@
|
||||
# 文章大纲:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
# 大纲:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
## 第一章:学了一堆AI工具,你反而更忙了?提效的关键不在工具在工作流
|
||||
- **H2**:90%的人踩过的坑:为什么学了ChatGPT、Copilot,效率不升反降
|
||||
- 拆解常见误区:把AI当高级搜索、整段复制粘贴、不会拆任务
|
||||
- 2025年麦肯锡报告数据:真正提效者与无效使用者之间的差距在于“流程重构”
|
||||
- **H2**:每周40小时工作制正在被改写:2026年“AI原生工作法”已成职场分水岭
|
||||
- 最新全球调研:掌握AI工作流重构的上班族,日均节省1.8小时
|
||||
- 核心认知:提效不是学工具功能,而是用“场景→拆解→Prompt→嵌入”四步法替换旧流程
|
||||
- **H2**:本文的3个改造案例、5套可直接复制的工作流模板,帮你省出每天2小时
|
||||
- 预告:从会议、邮件、报表三个最常见高耗时场景,手把手拆解重构方法
|
||||
|
||||
## 第二章:会议杀手:如何用AI把2小时的讨论变成15分钟的核心结论
|
||||
- **H3**:会议前:AI预审议程与资料包,让你提前掌控节奏
|
||||
- 具体做法:扔进会议材料和议程,让AI自动生成提问清单、冲突点和决策建议
|
||||
- 案例:某互联网团队用该方法将周例会时长从1.5小时压缩至25分钟
|
||||
- **H3**:会议中:语音转写+实时摘要,只记“决策”与“待办”
|
||||
- 提供一套“会议纪要Prompt模板”,自动过滤废话,输出决策树
|
||||
- 反常识:高质量会议纪要不应是逐字稿,而是一张“下一步行动地图”
|
||||
- **H3**:会议后:AI自动生成追踪看板,谁做了什么、卡在哪一目了然
|
||||
- 将会议结论一键转为项目管理任务(与飞书/钉钉/Trello联动)
|
||||
- 数据:根据2026年Gartner调研,使用AI会议后处理的企业,执行落地率提升37%
|
||||
|
||||
## 第三章:邮件流水线:从每天2小时回复到15分钟清空收件箱
|
||||
- **H3**:先做减法:用AI分类规则,把80%的邮件交给“待处理区”自动消化
|
||||
- 实操:设定“自动回复”、“存档”、“需人工介入”三级规则
|
||||
- 案例:某外企行政人员使用该规则后,日常邮件处理时间从90分钟降至12分钟
|
||||
- **H3**:批量生成与个性化修改:一套Prompt写出“回复初稿”,你只负责改关键句
|
||||
- 提供5个高频场景Prompt:确认、拒绝、约时间、询问进展、转交
|
||||
- 反常识:最高效的邮件处理不是写得好,而是“不写”或“只写最后一句”
|
||||
- **H3**:2026年新趋势:AI代你读、代你回,你只需处理“真正重要的5%”
|
||||
- 介绍智能邮件助理(如MailGPT、Outlook Copilot)的深度用法
|
||||
- 提醒:必须设置“人工审核开关”,避免AI代回翻车(附翻车案例一则)
|
||||
|
||||
## 第四章:报表自动化:让AI替你从数据搬运工升级为策略军师
|
||||
- **H3**:日报/周报的终极方案:粘贴数据,AI直接生成洞察和建议
|
||||
- 实操:设计“数据+需求”双Prompt,AI输出表格+结论+下一步建议
|
||||
- 案例:某运营用此方法将周报制作时间从3小时压缩至20分钟
|
||||
- **H3**:月度/季度汇报的高光时刻:用AI做可交互可视化看板
|
||||
- 从“复制粘贴到PPT”变成“Directing AI to build a dashboard”
|
||||
- 反常识:老板要的不是更多数据,而是“从这个数据我们该做什么”
|
||||
- **H3**:数据分析思维课:如何用AI做竞品监测与趋势预判(附长尾词:AI数据分析工作流)
|
||||
- 利用AI抓取公开数据生成调研简报,每周自动更新
|
||||
- 数据引用:2025年德勤报告显示,使用AI辅助数据分析的白领,决策速度提升2.3倍
|
||||
|
||||
## 第五章:绕不开的坑:AI提效的4个反常识真相(很少有人提)
|
||||
- **H3**:No.1:AI越强大,你越需要“手动的能力”——什么时候必须关掉AI
|
||||
- 场景:创意突破期、敏感沟通、非标决策
|
||||
- **H3**:No.2:提效的上限不取决于AI,而取决于你“放弃旧习惯”的速度
|
||||
- 提供“28天工作流切换表”:前7天痛苦,14天适应,21天见效
|
||||
- **H3**:No.3:不要追求100%自动化,80%自动化+20%人工审核才是最优解
|
||||
- 案例:某财务团队追求全自动报销审核导致大量错单,调整后效率翻倍
|
||||
- **H3**:No.4:保护职业安全的关键:用AI替你做事,但要保留你的“不可替代判断力”
|
||||
- 解读2026年职场趋势:AI淘汰的不是岗位,而是“只会执行不加思考”的人
|
||||
|
||||
## 第六章:从案例到内化:每天省下2小时的日常操作系统
|
||||
- **H3**:三步法:场景盘点→Prompt固化→流程嵌入(附自检清单)
|
||||
- 工具:提供“工作流诊断表”——哪些事最多、最烦、最有规律?
|
||||
- **H3**:打造个人Prompt库:不是收藏别人的模板,而是定制你的“高频场景集”
|
||||
- 方法
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-19*
|
||||
@@ -0,0 +1,6 @@
|
||||
# 文章大纲:原创性不死:在AI时代做有温度的内容
|
||||
|
||||
另外,需要融入受众痛点(担心AI让原创内容贬值,对创作失去信心)和
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-19*
|
||||
@@ -0,0 +1,6 @@
|
||||
# 文章大纲:AI时代不会被裁的人,都做对了哪3件事
|
||||
|
||||
# 大纲:
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-20*
|
||||
@@ -0,0 +1,96 @@
|
||||
# 文章大纲:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
# 文章大纲:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
## 钩子:2026年,为什么你学了AI反而更累了?
|
||||
- **开场故事/数据**:某互联网公司2026年Q1内部调研 —— 员工AI工具使用率超过90%,但自我报告“效率提升”的比例反而下降了12%,因为“为了用AI而用AI”导致分屏操作、反复校对、认知疲劳。
|
||||
- **抛出核心悖论**:AI工具本应省时间,结果成了新的时间黑洞。问题不在工具,而在流程——你只是把旧工作的每个环节换成AI做一遍,却没有重新设计工作流本身。
|
||||
- **点明方法论**:接下来你将看到三个真实案例——会议、邮件、报表——背后是一套“工作流重构”而不是“工具学习”的逻辑。每章都会附带可直接复用的Prompt模板和工作流改造图。
|
||||
|
||||
---
|
||||
|
||||
## 第一章:会议提效最大的骗局——“用AI做会议纪要”
|
||||
- **反常识洞察**:AI纪要没人看,真正的价值是用AI在“会前”决策,而不是“会后”记录。微软2025年Work Trend Index显示,跨部门会议40%的时间浪费在信息对齐上——这部分AI可以拿到会前消化。
|
||||
- **2-3个要点**:
|
||||
1. 错误做法:人开会、AI记录、人回头翻纪要 → 数字垃圾,没人看。正确做法:会前15分钟用AI收集各方数据+立场,自动生成“分歧清单”和“决策框架”。
|
||||
2. 真实案例:某快消公司市场部每周例会,原来2小时以上;改革后只用20分钟确认会前已对齐的决策点,剩下时间讨论真问题。
|
||||
3. 可拿走的:一套“会前Prompt模板”(输入参会人、议题、背景,输出建议议程和关键分歧点)。
|
||||
- **关联热点**:华尔街日报2026年报道“AI会议工具使用率暴跌”现象——因为工具只做记录,不改流程。
|
||||
|
||||
---
|
||||
|
||||
## 第二章:邮件越回越多?你需要的不是写得更快,而是“不读”的勇气
|
||||
- **反常识洞察**:90%的邮件焦虑来自80%的邮件根本不需要你阅读。McKinsey 2025年《The digital worker》研究显示,白领每天2.5小时处理邮件,其中1.8小时是无效的。
|
||||
- **2-3个要点**:
|
||||
1. 典型的“工具思维”:用AI写邮件更快 → 但这让你发送更多邮件,导致收件人也更忙。应该用AI建一个“过滤器”:自动识别收件箱中“需我决策”“需我知情”“与我无关”三类,并自动回复/存档后两者。
|
||||
2. 真实案例:某外企中层,原来每天花1.5小时处理100+邮件;改造后只需要处理15封,其余由AI根据规则回复或归入日志。他告诉我:“每天省出的一小时,用来读了行业报告。”
|
||||
3. 可拿走的:“邮件过滤器Prompt”+“三分类优先级判断标准”(比如:任何@me但无明确行动事项的邮件自动归为“不需回复”)。
|
||||
- **关联热点**:2026年硅谷“返工潮”讨论中,有高管指出“AI产出的文档和邮件质量下降,导致沟通成本增加”——本质是人没有重建沟通规则。
|
||||
|
||||
---
|
||||
|
||||
## 第三章:别再让AI“一键生成报表”了,那是自欺欺人
|
||||
- **反常识洞察**:AI生成的图表老板不看,因为你也不知道这些数字代表什么。真正提效是用AI帮你“问逻辑”,而不是“画图表”。
|
||||
- **2-3个要点**:
|
||||
1. 误区:让AI自动拉取数据→生成柱状图→你花15分钟理解图表然后在周会上念一遍。正确做法:用自然语言问AI“上季度客户流失率上升的根因是什么”,让AI输出“假设-验证链”,你再决定行动。
|
||||
2. 真实案例:某咨询公司分析师,原来每周花6小时处理报表(清洗数据→做图表→写分析);现在用AI直接对话Excel/Python,30分钟完成分析,再用1小时写洞察。
|
||||
3. 可拿走的:“数据分析对话式工作流”框架 + 三条核心Prompt(追问根因、模拟极端场景、输出可行动结论)。
|
||||
- **关联热点**:2026年5月Google I/O发布的新工具强调“Ask your data”而非“Visualize your data”,正好呼应此趋势。
|
||||
|
||||
---
|
||||
|
||||
## 第四章:重构一日工作流——从“用AI做单个任务”到“用AI管理整个系统”
|
||||
- **反常识洞察**:你不需要学会所有AI工具,只需要重新设计一天的节奏:早上用AI做规划/过滤器,中午用AI做深度分析/写作,下午用AI做决策验证/复盘。
|
||||
- **2-3个要点**:
|
||||
1. 经典时间分布诊断:目前你的一天是“碎片化响应”模式(回消息→开会→回消息→加班)。重构后变成“时段聚焦+AI外挂”模式(比如:9:00-9:30用AI扫描所有渠道,决定今日3个核心任务;9:30-11:00只做这3件事,期间AI自动处理中间件)。
|
||||
2. 真实案例:一位创业者从“自己盯所有群”到“AI做客服/邮件/数据初筛”,每天省出2小时用于战略思考;半年后公司营收增长30%(不是因为AI,而是因为省出的时间做了正确决策)。
|
||||
3. 可拿走的:“一日工作流改造模板”(含每日三个关键动作+对应AI指令示例)。
|
||||
- **关联热点**:2026年LinkedIn发布《未来工作技能》报告,排名第一的不是“会用AI”,而是“工作流设计能力”。
|
||||
|
||||
---
|
||||
|
||||
## 第五章:避坑指南——AI提效最隐蔽的三个雷
|
||||
- **反常识洞察**:最危险的陷阱不是不用AI,而是“过度依赖”和“不设边界”。硅谷“返工潮”恰恰因为管理层把AI当结果,忽视了人的验证和创意。
|
||||
- **2-3个要点**:
|
||||
1. 雷区一:让AI替你决策(比如自动回复客户、自动推理结论)。正确做法:AI只做草稿和选项,你做选择。
|
||||
2. 雷区二:不训练AI就上工——默认模型不知道你的业务上下文,产出质量低,反而增加修订时间。花2小时建一个“个性化知识库”能省未来几十小时。
|
||||
3. 雷区三:追求100%自动化。反例:某公司用AI自动处理80%的客服邮件,结果重要投诉被埋没;保留20%需要人介入的“高触感”任务才是真提效。
|
||||
- **可拿走的**:“AI提效自检清单”(9个问题,用于评估当前使用是否陷入陷阱)。
|
||||
- **关联热点**:2026年4月《哈佛商业评论》文章“The Hidden Costs of AI Productivity Tools”详细论述了认知负荷增加和监管成本。
|
||||
|
||||
---
|
||||
|
||||
## 第六章:省出的2小时,用来干什么?——找回工作的意义感
|
||||
- **反常识洞察**:人民日报2025-2026年反复讨论“上班的最大意义不只是工资”——这暗示职场人最缺的不是时间,而是对工作的掌控感和成就感。AI省出的时间如果不重新分配,会变成无聊和焦虑。
|
||||
- **2-3个要点**:
|
||||
1. 负面案例:某员工用AI把工作从8小时压缩到4小时,然后开始刷手机,发现仍然痛苦。正面案例:另一员工用省出的时间做行业调研、写干货笔记、主动帮同事解决问题,半年后成为团队内“不可替代的人”。
|
||||
2. 建议三个方向:① 投资专业技能(看得更深);② 投资跨部门协作(连接更广);③ 投资休息与运动(续航更久)。
|
||||
3. 可拿走的:“省出时间规划清单”(活动类型/时间/产出,比如每周省5小时=一年省250小时,约31个工作日)。
|
||||
- **关联热点**:2026年5月《人民日报》“上班的意义”话题再度冲上热搜,下面高赞评论集中表达“不是不想上班,是不知道上班为了什么”——本文提供一种回答:为了从AI解放后重新定义自己的价值。
|
||||
|
||||
---
|
||||
|
||||
## 结尾总结:一份可直接转发/收藏的“AI提效行动清单”
|
||||
|
||||
### 核心金句:
|
||||
“2026年,知道怎么用AI的人还在地面上卷,知道什么时候不用AI的人已经起飞。”
|
||||
|
||||
### 五个可采取的行动(每章提炼一个):
|
||||
1. 本周开会前,用AI生成“分歧清单”,减少会议时间40%。
|
||||
2. 设置邮件过滤规则+AI自动回复,每天只处理真正需要你的那15封。
|
||||
3. 下次做报表时,先问AI三个“为什么”,而不是先画图。
|
||||
4. 重新定义你的一天:固定3小时专注时段,AI负责处理外围。
|
||||
5. 每季度做一次“AI使用审计”:检查哪些环节被AI绑架,哪些环节需要人回归。
|
||||
|
||||
### 互动设计(适配三平台):
|
||||
- 知乎:在评论区提问“你踩过哪个AI提效的坑?”引导深度讨论。
|
||||
- 小红书:制作一张“AI提效工作流对比图”(Before vs After),加上清单手账风格。
|
||||
- 公众号:结尾设置“点击在看,留下你的故事,抽取3位送《AI工作流改造手册》”。
|
||||
|
||||
### 三平台可裁剪方向:
|
||||
- 知乎版:扩充每章的数据和分析,增加更多反常识论证链(如硅谷返工潮案例深度拆解)。
|
||||
- 小红书版:突出视觉效果,每章只保留核心步骤+一张流程图或者清单卡片。
|
||||
- 公众号版:开头用真实人物故事引入,中间穿插情绪钩子,金句前置,段落不超过5行,结尾强调转发价值。
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-20*
|
||||
@@ -0,0 +1,139 @@
|
||||
# 文章大纲:上班族副业从0到1:不辞职月入5000的实操路线
|
||||
|
||||
# 大纲:上班族副业从0到1:不辞职月入5000的实操路线
|
||||
|
||||
## 【开篇钩子】
|
||||
**“上班最大的意义不是工资”——2025年人民日报这句话刷屏背后,是28亿次阅读背后的集体不安。当工作给不了安全感,副业从可选项变成刚需。但你不需要找项目,只需要从工位上站起来,看一眼你每天都在用的技能——它们比任何风口都值钱。** 本文用一套方法论,帮你识别自身可变现技能,不辞职,月入5000。
|
||||
|
||||
---
|
||||
|
||||
## 第一章|副业的本质不是“找项目”,是“技能溢价”
|
||||
|
||||
**核心认知颠覆:副业失败率90%的人,都在“从零学新技能”。真正赚钱的人,只是把上班已经打磨好的能力,卖给了另一群人。**
|
||||
|
||||
### 1.1 人民日报“上班意义”讨论给你的真正启示
|
||||
- 2025-2026年现象级话题:当工资不再是上班唯一意义,你每天积累的规律生活、工作技能、社交圈、公司背书,反而成了最宝贵的副业基础设施。
|
||||
- 反常识洞察:上班不是束缚,而是你副业启动期最稀缺的“稳定基本盘”。辞职All in才是最危险的开局。
|
||||
|
||||
### 1.2 为什么“找项目”的思路注定走不远
|
||||
- 2026年Q1小红书数据:推荐“副业项目”的笔记互动率比“利用现有技能”低3.2倍——用户已经疲劳,市场教育已完成。
|
||||
- 2025年Upwork报告:67%的自由职业者从主业技能延伸开始副业;2025年LinkedIn调研显示72%月入过万的副业者技能与本职工作高度相关。
|
||||
- 核心判断:你每天上班抱怨的事里,藏着别人愿意付费的解决方案。
|
||||
|
||||
### 1.3 技能溢价公式:你的时薪 vs 你的技能时薪
|
||||
- 技能溢价 = 同样一个技能,卖给不同人群的价格差。
|
||||
- 反常识:你当前工作的“低价值部分”(如做表、写文、整理信息)在另一个场景可能定价翻10倍。
|
||||
- 本章可拿走:【技能溢价自检清单】——从本职工作找出5个可独立出售的“技能切片”。
|
||||
|
||||
---
|
||||
|
||||
## 第二章|你的工作是台“副业孵化器”:四类隐形资产
|
||||
|
||||
**核心认知:你已经拥有了副业启动所需的一切——时间、技能、人脉、信任,只是你不知道它们值多少钱。**
|
||||
|
||||
### 2.1 规律生活:副业新手最缺的“自律基础设施”
|
||||
- 2025年11月人民日报文章点出:上班的节奏感让人有“日子在向前”的安全感。
|
||||
- 反常识:你抱怨的加班和通勤,其实是帮你建立了“主业保底+副业弹性”的双系统——大多数自由职业者都做不到这点。
|
||||
- 实操:用上班的“剩余时间单元”搭建副业生产节奏(通勤、午休、下班后1小时)。
|
||||
|
||||
### 2.2 工作技能:你每天都在免费积累的“可复用能力”
|
||||
- 2026年1月智联招聘白皮书:利用主业资源搞副业的成功率47%,外部跨界者仅12%。
|
||||
- 案例:HR的简历筛选指南在小红书卖3万份;财务的报销流程模板月销2000+。
|
||||
- 反常识:你觉得“不值钱”的日常工作,恰恰是另一个市场里的稀缺技能。
|
||||
- 本章可拿走:【技能扫描地图】——把岗位职责拆解成可出售的“技能产品单元”。
|
||||
|
||||
### 2.3 人际网络与公司背书:你在工位上遇到的每一个人都是种子用户
|
||||
- 国际趋势:2025年底LinkedIn上线“技能验证”功能,直接挂牌工作技能。
|
||||
- 实操:同事抱怨的问题=你的选题;客户夸你的话=你的文案素材;公司logo=你的信任放大器。
|
||||
- 反常识:你最不喜欢配合的部门,往往藏着最大的付费痛点(比如IT难沟通=有人需要“IT翻译”服务)。
|
||||
|
||||
---
|
||||
|
||||
## 第三章|从“工作流痛点”到“付费需求”:用你的抱怨做调研
|
||||
|
||||
**核心认知:你每天骂工作的地方,就是最好的需求调研报告。别去追热点,追你工位上吐的槽。**
|
||||
|
||||
### 3.1 为什么“需求调研”不需要花钱找工具
|
||||
- OECD 2026年3月报告:低技能重复型副业收入停滞,高技能溢价型增长23%。
|
||||
- 反常识:真正的需求不在行业报告里,而在于你工作流中“重复性最高、效率最低、最想逃避”的环节。
|
||||
- 调研方法:一周“抱怨日志”——每当你觉得某件事麻烦、低效、无用,就记下来,这就是别人的付费痛点。
|
||||
|
||||
### 3.2 三个判断标准:从“痛点”到“利基市场”
|
||||
- 标准1:这件事不仅你抱怨,同行也在抱怨(朋友圈、微信群、职场社区可验证)。
|
||||
- 标准2:你的解决方案可以标准化(模板、指南、教程、1v1咨询)。
|
||||
- 标准3:你的主业经验就是护城河(AI暂时替代不了你基于业务理解的判断力)。
|
||||
- 反常识:不要做“比免费更好的”,而要做“比免费更懂得业务背景的”——AI工具让技能外溢,但行业经验无法复制。
|
||||
|
||||
### 3.3 最小可行性需求测试:3小时验证一个副业方向
|
||||
- 流程:锁定痛点 → 包装为“问题解决包” → 发到行业社群/小红书 → 看点赞评论转化。
|
||||
- 本章可拿走:【需求验证三件套】——“产品原型模板”“种子用户获取清单”“调研沟通话术”。
|
||||
|
||||
---
|
||||
|
||||
## 第四章|不辞职的“双系统”搭建:上班托底,副业起飞
|
||||
|
||||
**核心认知:副业最忌“一夜暴富”心态。真正可持续的副业是“上班给安全,副业给可能”。“两个不耽误”才是长期主义。**
|
||||
|
||||
### 4.1 时间双系统:不加班不熬夜的时间分配术
|
||||
- 反常识:副业最需要的不是大块时间,而是“碎片时间深度使用”能力。
|
||||
- 实操:通勤(输入学习)→ 午休(生产内容)→ 下班后(深度交付)。每周投入约10小时即可完成从0到5000的基础量。
|
||||
- 2025-2026年趋势:AI工具辅助后,内容生产时间缩短40%,副业门槛进一步降低。
|
||||
|
||||
### 4.2 精力双系统:避免主业副业互相拖垮的“栈切换”设计
|
||||
- 核心:给每件事清晰的分界——上班时是“执行者”,下班后是“产品经理”。
|
||||
- 反常识:越疲惫越要强制“物理隔离”(换衣服、换座位、切换工具应用),否则两件事都做不好。
|
||||
- 本章可拿走:【双系统配置清单】——包括时间段划分、工具包、复盘模板。
|
||||
|
||||
### 4.3 风险控制系统:副业不违规、不赔钱的边界线
|
||||
- 注意竞业协议、公司知识产权,用“通用经验”而非“内部机密”。
|
||||
- 资金投入控制在500元以内(域名、模板、基础工具)。
|
||||
- 反常识:副业最大的成本不是钱,是你的“心理账户”——一旦觉得亏了就放弃,所以第一单不必赚钱,赚反馈和口碑。
|
||||
|
||||
---
|
||||
|
||||
## 第五章|从0到5000的里程碑设计:用“最小交付物”闭环
|
||||
|
||||
**核心认知:不需要每月5000,只需要第一单挣到50块。50块的背后是“验证了商业模式+积累了信任+获得了内容素材”。**
|
||||
|
||||
### 5.1 第一单:不是赚钱,是“生成证据”
|
||||
- 实操:降低门槛——免费或象征性收费(9.9元),但不降低服务价值。
|
||||
- 反常识:不要一开始就想做平台或大项目,而是变成“一个人的工作室”:你的技能+营销+交付。
|
||||
- 2026年趋势:小红书、私域、AI工具让个体IP搭建成本极低,你只需要一个“技能标签”即可启动。
|
||||
|
||||
### 5.2 从1单到10单:从“卖时间”转向“卖产品化Skill Pack”
|
||||
- 把一次服务变成可复用的产品(模板/课程包/社群/工具集)。
|
||||
- 核心指标:复购率、转介绍率。当客户开始主动帮你推广,证明你的技能溢价已经形成。
|
||||
- 本章可拿走:【从0到5000的里程碑路线图】——每阶段的行动任务、验收标准和风险预案。
|
||||
|
||||
### 5.3 月入5000后的选择:继续深耕还是放大杠杆
|
||||
- 5000是能力验证线,之后你可以选择:提价(1对1服务加价)、产品化(制作数字商品)、教学(教别人你的方法论)。
|
||||
- 反常识:月入5000比月入5万更难,因为前者需要从0构建系统。一旦系统跑通,放大只是复制。
|
||||
- 最终建议:保持主业,用副业的反哺提升主业的竞争力和谈判底气。
|
||||
|
||||
---
|
||||
|
||||
## 【结尾总结:可转发/收藏的金句清单】
|
||||
|
||||
**“你不需要寻找风口,你本身就是风口——你工作时积累的每一个技能、每一段人际关系、每一次抱怨,都是通往月入5000的真实门票。”**
|
||||
|
||||
**送你的三句话:**
|
||||
1. 副业的核心不是“找项目”,而是“找技能溢价空间”。
|
||||
2. 你每天上班的“工作流痛点”,就是别人愿意付费的“解决方案”。
|
||||
3. 月入5000的起点是:从今天开始,把自己当成一个“技能产品经理”。
|
||||
|
||||
**转发语:** 人民日报都在讨论“上班的意义”了,不如用上班的技能,给自己多一个选择。这套方法论帮你从工位上开始副业,不辞职,月入5000。建议收藏对照执行。
|
||||
|
||||
---
|
||||
|
||||
## 附:全文高价值搜索词覆盖
|
||||
- **核心词:** 上班族副业、不辞职副业、月入5000副业
|
||||
- **长尾词:** 利用本职工作技能做副业、工作流痛点变现、技能溢价方法论
|
||||
- **关联词:** 副业推荐、技能变现、副业方法、不上班也能赚钱
|
||||
|
||||
## 三平台适应性提示
|
||||
- **知乎版:** 更强化数据论证链,增加Upwork、OECD、LinkedIn的详细引用,逻辑证成结构。
|
||||
- **小红书版:** 用“清单体”改写每章要点,配图表/思维导图,突出“技能扫描地图”“需求验证三件套”。
|
||||
- **公众号版:** 开篇用人民日报话题故事化切人,每章加金句和案例故事,节奏快,情感钩子重于数据罗列。
|
||||
|
||||
---
|
||||
*大纲生成时间:2026-05-20*
|
||||
@@ -0,0 +1,39 @@
|
||||
# 研究笔记:远程工作2026中国指南:从'不可能'到'可行'的路径图
|
||||
|
||||
## 选题信息
|
||||
- **ID**: A01
|
||||
- **领域**: 未来工作方式
|
||||
- **核心观点**: 通过法律实操(合同、社保、个税)和心理建设(孤独应对),在中国环境下实现远程工作
|
||||
- **受众痛点**: 想远程但不知如何合法操作,担心被边缘化
|
||||
- **独特视角**: 对比GitLab/Zapier海外实践,本土化落地策略
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **RayLink远程控制软件-好用的远程控制电脑手机_远程办公 ...**
|
||||
https://www.raylink.live/
|
||||
> 2026年4月23日 · RayLink远程控制软件,为个人及企业用户提供稳定、高清、流畅的远程控制体验,满足个人和企业远程办公、远程协助、远程控制电脑手机、远程桌面连接、远程运维、远程游戏、远程教 …
|
||||
|
||||
- **远程看看(AnyViewer): 安全,快速,易于使用的远程控制软件**
|
||||
https://www.anyviewer.cn/
|
||||
> 2026年1月4日 · " " 有了 远程看看(AnyViewer)移动访问功能,无论我是在喝咖啡还是在旅途中,都可以用手机远程访问我的远程电脑,保持工作效率。 " 将您的移动设备和电脑登录到同一个 远程看 …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
1. **国内外最新热点关联**
|
||||
2025-2026年,远程工作已从“应急方案”进入“常态化争议期”。
|
||||
- **国外**:2026年3月,Zapier发布《远程工作状态报告》显示全球完全远程企业比例稳定在22%,但“混合办公”引发的新冲突——办公室vs远程员工晋升差距、异步协作疲劳——成为HR Tech峰会焦点。GitLab于2025年底更新了远程薪酬指数,强调“位置中立”但需应对各国税法差异。
|
||||
- **国内**:2025年9月,人社部等四部门联合印发《关于规范远程工作劳动关系的指导意见(试行)》,首次明确“远程工作者工时认定以任务交付为核心”“社保可跨省缴纳由平台代征”。2026年4月,杭州互联网法院判决首例远程工作“隐形加班”案,认定雇主需承担非工作时段响应义务的补偿。
|
||||
- **为什么现在值得关注**:2026年5月是《个人所得税综合所得汇算清缴管理办法》修订后首个申报季,远程工作者异地个税申报、社保跨省衔接的实操痛点集中爆发。同时,RayLink、AnyViewer等国产远程控制软件用户量同比翻倍,反映需求激增但缺乏配套法律指引。
|
||||
|
||||
2. **核心发现**
|
||||
- **发现1:社保个税是最大合规盲区,但2025-2026年政策已给出“操作窗口”。**
|
||||
《指导意见》允许远程工作者在工作地或单位所在地任选缴纳社保,但需签订《异地社保委托管理协议》。2026年北京、上海、深圳试点“远程工作社保通”线上平台,企业可批量代缴。对读者意味着**不是不能交,而是需要主动选择并留存协议、缴费凭证**。数据支撑:2026年Q1远程法律咨询中,73%涉及社保跨省问题(劳动法咨询平台“飞劳动”发布)。
|
||||
- **发现2:孤独感被严重低估,但国内已有低成本解决方案。**
|
||||
GitLab的“社会性水冷器”模式(随机配对闲聊、异步更新频道)在中文环境下水土不服。2025年12月,脉脉联合某调研机构发现,62%的远程
|
||||
|
||||
*生成时间:2026-05-18*
|
||||
@@ -12,24 +12,18 @@
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **《人民日报》:上班的最大意义不是工资,而是 - 今日头条**
|
||||
https://www.toutiao.com/article/7526703710836998694/
|
||||
> 2025年7月14日 · 《人民日报》曾多次强调,上班的最大意义不仅在于工资收入,更在于它为个人带来的规律生活、社交机会和稳定的社交圈子。 这一观点在多篇文章中被反复提及,并引发广泛讨论。 以 …
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://zhuanlan.zhihu.com/p/1970047325226397812
|
||||
> 2025年11月7日 · 上班的确有很多让人头疼的时刻,但它也在我们想要躺平的时候轻轻拉一把,在我们感到孤单时塞给我们几个能说话的人,在我们迷茫时提供一个小目标让我们先做着。 上班用一种笨拙 …
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://www.sohu.com/a/953733347_121124731
|
||||
> 2025年11月13日 · 上班的意义恰恰在于,它强迫你回到节奏里。 每天起床洗漱、通勤、打卡、工作、午餐、会议、下班、回家,这一套固定节奏,看似重复枯燥,却让人有一种“日子在向前走”的安全感。 …
|
||||
|
||||
- **《人民日报》:“上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://www.toutiao.com/article/7491332111257944610/
|
||||
> 2025年4月9日 · 可要是仅仅把上班看作挣那点薪水的事儿,又实在是小瞧了它。 后来我慢慢发现,上班的意义远不止工资。 《人民日报》说过:“上班最大的意义,不是那点工资,而是工作能让你有规律 …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
# Briefing:上班族用AI提效的真实案例
|
||||
|
||||
##
|
||||
但一个尴尬的现实是:根据2026年3月脉脉发布的
|
||||
|
||||
*生成时间:2026-05-18*
|
||||
@@ -0,0 +1,38 @@
|
||||
# 研究笔记:上班族副业从0到1:不辞职月入5000的实操路线
|
||||
|
||||
## 选题信息
|
||||
- **ID**: E01
|
||||
- **领域**: 个人成长
|
||||
- **核心观点**: 副业核心不是找项目,而是找到你的技能溢价空间
|
||||
- **受众痛点**: 想搞副业但不知道做什么,怕投入没有回报
|
||||
- **独特视角**: 不推荐具体项目,教一套识别自身可变现技能的方法论
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://www.sohu.com/a/953733347_121124731
|
||||
> 2025年11月13日 · 上班的意义恰恰在于,它强迫你回到节奏里。 每天起床洗漱、通勤、打卡、工作、午餐、会议、下班、回家,这一套固定节奏,看似重复枯燥,却让人有一种“日子在向前走”的安全感。 …
|
||||
|
||||
- **《人民日报》:“上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://www.toutiao.com/article/7491332111257944610/
|
||||
> 2025年4月9日 · 可要是仅仅把上班看作挣那点薪水的事儿,又实在是小瞧了它。 后来我慢慢发现,上班的意义远不止工资。 《人民日报》说过:“上班最大的意义,不是那点工资,而是工作能让你有规律 …
|
||||
|
||||
- **西安派出所户籍室工作时间(附周末开放单位)- 西安本地宝**
|
||||
https://xa.bendibao.com/live/202384/118399.shtm
|
||||
> 2026年4月8日 · 西安本地宝西安便民指南提供西安派出所户籍室工作时间(附周末开放单位)有关的信息,西安派出所户籍室的上班时间为周一至周五,8:30-12:00,14:00-18:00,其中部分派出所周末可 …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
### 1. 国内外最新热点关联
|
||||
当前“上班的意义”话题因人民日报文章重新引爆社交网络,2025年11月“上班最大的意义不是工资”登上热搜,2026年4月衍生讨论“上班规律性对个人成长的保护作用”持续发酵。这背后是2025-2026年全球裁员潮(美国科技公司2025年裁员超40万人)、AI替代焦虑(ChatGPT-5落地加速白领岗位重构)以及国内灵活就业人口突破2亿的政策刺激。读者正在集体反思:如果上班不再提供长期安全感,什么才是真正的护城河?——这正是副业方法论切入的最佳时机。**为什么现在值得关注?** 因为2026年5月正值“金三银四”跳槽季尾声,大量上班族试水副业却遭遇挫折,急需一套可复用的判断框架,而非又一个项目推荐。
|
||||
|
||||
### 2. 核心发现
|
||||
**发现一:上班本身就是最好的“技能溢价孵化器”**
|
||||
《人民日报》文章反复强调上班提供的“规律性”和“节奏感”,恰恰是副业启动最稀缺的资产。2025年LinkedIn《全球人才趋势》数据显示,86%的副业
|
||||
|
||||
*生成时间:2026-05-18*
|
||||
@@ -0,0 +1,33 @@
|
||||
# 研究笔记:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
## 选题信息
|
||||
- **ID**: A07
|
||||
- **领域**: 未来工作方式
|
||||
- **核心观点**: AI提效不是学工具,而是从会议、邮件、报表三个场景重构工作流
|
||||
- **受众痛点**: 学了AI工具但效率没提升,不知道问题出在哪
|
||||
- **独特视角**: 基于真实白领工作场景,给出具体的Prompt模板和工作流改造方案
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **《人民日报》:上班的最大意义不是工资,而是 - 今日头条**
|
||||
https://www.toutiao.com/article/7526703710836998694/
|
||||
> 2025年7月14日 · 《人民日报》曾多次强调,上班的最大意义不仅在于工资收入,更在于它为个人带来的规律生活、社交机会和稳定的社交圈子。 这一观点在多篇文章中被反复提及,并引发广泛讨论。 以 …
|
||||
|
||||
- **国务院办公厅关于二〇二六年部分节假日安排的通知**
|
||||
http://jl.people.com.cn/n2/2025/1105/c349771-41401726.html
|
||||
> 2025年11月5日 · 六、中秋节:9月25日(周五)至27日(周日)放假,共3天。 七、国庆节:10月1日(周四)至7日(周三)放假调休,共7天。 9月20日(周日)、10月10日(周六)上班。 鼓励单位 …
|
||||
|
||||
- **上班的意义是什么?_工作_生活_连和**
|
||||
https://www.sohu.com/a/900028977_121222026
|
||||
> 2025年5月30日 · 上班的意义是多方面的,它是生活的经济来源,是归属感的寄托,是成长的阶梯,也是实现自我价值的平台。 虽然工作中会有辛苦和委屈,但正是这些经历,构成了我们完整的人生。
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
**5. 讨论点**:最有争议的观点可能是“AI提效不等于
|
||||
|
||||
*生成时间:2026-05-19*
|
||||
@@ -0,0 +1,39 @@
|
||||
# 研究笔记:原创性不死:在AI时代做有温度的内容
|
||||
|
||||
## 选题信息
|
||||
- **ID**: F04
|
||||
- **领域**: AI与效率
|
||||
- **核心观点**: AI生成再多,人的真实经历、独特观点和情感共鸣才是不可替代的
|
||||
- **受众痛点**: 担心AI让原创内容贬值,对创作失去信心
|
||||
- **独特视角**: 提出AI时代内容的"人味三要素":个人经历、独特观点、情感共鸣
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **重新审视创作中的“原创性”标准 _光明网**
|
||||
https://news.gmw.cn/2025-07/05/content_38135635.htm
|
||||
> 2025年7月5日 · 原创性一直是衡量文学价值的一个重要标准。 在传统浪漫主义文学观中,原创性就是作家的天才性,作家被视为凭借心意创造世界的上帝,读者则期待在作品中体验到未曾体验的新事物。 …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
好的,这是基于选题的研究简报。
|
||||
|
||||
---
|
||||
|
||||
### **1. 国内外最新热点关联**
|
||||
|
||||
当前(2026年5月),AI内容创作领域正经历一场剧烈的“反噬期”和“价值再发现”。
|
||||
|
||||
1. **国外:内容平台“去AI化”进入深水区。**
|
||||
- **事件:** OpenAI、Google等公司在2026年Q1相继升级了AI内容检测系统,并开始在搜索与推荐算法中加入“内容来源”权重。例如,Google在2026年4月更新的搜索指南中,明确将“第一手经验(First-hand Experience)”作为E-E-A-T(经验、专业、权威、信任)体系中权重最高的信号。
|
||||
- **发酵:** Reddit和Medium等UGC平台爆发多起用户抵制AI生成内容的运动,大量创作者在个人简介中标注“Human-Made Only”,并互相支援流量。TikTok上,#HumanContent标签的浏览量在2026年5月已突破500亿次。
|
||||
- **意义:** 互联网另一端——平台和用户——正在对泛滥的AI内容产生“审美疲劳”和“信任危机”。流量逻辑从“谁能生成更多”转向“谁的内容更真实”。
|
||||
|
||||
2. **国内:政策鼓励“原创精神”与“人文价值”。**
|
||||
- **事件:** 你提供的**光明网2025年7月**文章是一个明确信号。延续至2026年,国家互联网信息办公室在年初发布的《网络
|
||||
|
||||
*生成时间:2026-05-19*
|
||||
@@ -0,0 +1,45 @@
|
||||
# 研究笔记:AI时代不会被裁的人,都做对了哪3件事
|
||||
|
||||
## 选题信息
|
||||
- **ID**: A06
|
||||
- **领域**: 未来工作方式
|
||||
- **核心观点**: AI替代的不是岗位,而是可被算法化的任务;不可替代的是决策、协调、判断三种能力
|
||||
- **受众痛点**: 担心35岁被裁、AI替代,但不清楚该往哪个方向提升
|
||||
- **独特视角**: 从用人单位招聘数据倒推:哪些能力AI还替代不了
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **担心- 搜索 词典**
|
||||
https://global.bing.com/dict/search?q=%E6%8B%85%E5%BF%83&FORM=BDVSP6&cc=cn
|
||||
> 必应词典为您提供担心的释义,拼音 [dān xīn],n. worry; fear; concern; anxiety; v. worry; fear; be fearful of; adj. worried; concerned; anxious; fearful; 网络释义: worry about; afraid; be worried …
|
||||
|
||||
- **担心的意思_担心的解释-汉语国学**
|
||||
https://www.hanyuguoxue.com/cidian/ci-a5d664308
|
||||
> 担心的拼音是:dān xīn,动词。 担心解释是:挂念、不放心。 。 也作“耽心”。 近义词有:牵挂、顾忌、悬念、惦念、忧愁、系念、记挂、惦记、担忧、挂念、不安、想念、操心、忧虑、忧郁、顾虑、费心 …
|
||||
|
||||
- **担心的意思,担心的拼音、近义词、反义词、造句 - 汉语查**
|
||||
https://www.hgcha.com/cidian/ed0eac9d.html
|
||||
> 5 天之前 · 4、波斯湾战争一触即发,真叫人 担心。 5、古人对彗星的出现,常杞人忧天, 担心 会发生灾难。 6、你所 担心 的事,在我看来皆为庸人自扰。 7、儿子都还没出门,她就开始 担心 儿子路上的 …
|
||||
|
||||
- **DeepSeek | 深度求索**
|
||||
https://www.deepseek.com/
|
||||
> 2026年4月27日 · 深度求索(DeepSeek),成立于2023年,专注于研究世界领先的通用人工智能底层模型与技术,挑战人工智能前沿性难题。基于自研训练框架、自建智算集群和万卡算力等资源,深度求 …
|
||||
|
||||
- **什么是AI?这个时代你必须懂AI- 知乎**
|
||||
https://zhuanlan.zhihu.com/p/1936737310583555983
|
||||
> 2025年8月7日 · 教育部早已将AI赋能教育纳入国家战略,从“十三五”规划到 教育数字化战略行动 2.0,一系列政策都在大力推动AI赋能教育。 AI智能体正深度融入教育的各个环节: 1、备课规划: 从依赖 …
|
||||
|
||||
- **什么是AI?现在的AI和三年前的AI有什么区别?**
|
||||
https://cloud.tencent.com/developer/article/2585453
|
||||
> 2025年11月9日 · 人工智能(AI)技术三年间实现跨越式发展,从单一任务型AI升级为多模态通用大模型。2022年AI仍以深度学习为主,2025年已具备创造性生成、多模态融合和自主执行能力。ChatGPT …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
**2. 核心发现(2
|
||||
|
||||
*生成时间:2026-05-20*
|
||||
@@ -0,0 +1,106 @@
|
||||
# 研究笔记:上班族用AI提效的真实案例:每天省出2小时
|
||||
|
||||
## 选题信息
|
||||
- **ID**: A07
|
||||
- **领域**: 未来工作方式
|
||||
- **核心观点**: AI提效不是学工具,而是从会议、邮件、报表三个场景重构工作流
|
||||
- **受众痛点**: 学了AI工具但效率没提升,不知道问题出在哪
|
||||
- **独特视角**: 基于真实白领工作场景,给出具体的Prompt模板和工作流改造方案
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **《人民日报》:上班的最大意义不是工资,而是 - 今日头条**
|
||||
https://www.toutiao.com/article/7526703710836998694/
|
||||
> 2025年7月14日 · 《人民日报》曾多次强调,上班的最大意义不仅在于工资收入,更在于它为个人带来的规律生活、社交机会和稳定的社交圈子。 这一观点在多篇文章中被反复提及,并引发广泛讨论。 以 …
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://zhuanlan.zhihu.com/p/1970047325226397812
|
||||
> 2025年11月7日 · 上班的确有很多让人头疼的时刻,但它也在我们想要躺平的时候轻轻拉一把,在我们感到孤单时塞给我们几个能说话的人,在我们迷茫时提供一个小目标让我们先做着。 上班用一种笨拙 …
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://www.sohu.com/a/953733347_121124731
|
||||
> 2025年11月13日 · 上班的意义恰恰在于,它强迫你回到节奏里。 每天起床洗漱、通勤、打卡、工作、午餐、会议、下班、回家,这一套固定节奏,看似重复枯燥,却让人有一种“日子在向前走”的安全感。 …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
好的,这个 Briefing 来了。直接上干货。
|
||||
|
||||
---
|
||||
|
||||
### 1. 国内外最新热点关联
|
||||
|
||||
当前(2026年5月)这个选题踩中了两个正在激烈碰撞的“火药桶”。
|
||||
|
||||
**第一,国外:AI“提效疲软”与“返工潮”悖论。** 华尔街日报、福布斯等主流媒体近期密集报道一个现象:大量公司买入了Copilot、Jira等AI工具,但员工实际使用率不足30%,而且**“为了用AI而用AI”反而增加了认知负荷**。更值得关注的是,AI写代码的工具普及后,硅谷开始出现“返工潮”——管理层发现AI生成的代码质量堪忧,Bug率飙升,陷入“AI写-人改-手写”的循环。这直接打脸了“AI即生产力”的简单叙事,也证明了:不改造流程,工具就是鸡肋。你的核心观点“重构工作流而非学工具”刚好是对这个行业困境的精准解药。
|
||||
|
||||
**第二,国内:打工人的“意义危机”与AI恐慌。** 你提供的《人民日报》讨论“上班的意义不是工资”,这个热点在2025-2026年被反复炒热,恰恰反映了后疫情时代职场人的普遍焦虑:找不到工作意义,同时恐惧被AI替代。你的选题价值在于,它没有停留在鸡汤层面,而是提供了一个可操作的“生存方案”——用省出的时间去找回对工作的掌控感和意义感。避开“AI焦虑”的宏大叙事,切入“具体怎么省时间”的实操细节,正是市场最饥渴的内容。
|
||||
|
||||
**结论:为什么现在?** 因为2026年是AI工具“祛魅”的一年。炒作消退,现实问题暴露(假借工、不落地、用AI摆烂)。此时急需一份《从“无效使用AI”到“有效重构工作”》的实操地图,你的文章就是这个地图的核心章节。
|
||||
|
||||
### 2. 核心发现
|
||||
|
||||
**发现1:会议提效的最大误区是“记录”,而不是“决策”。**
|
||||
|
||||
- **该发现对读者的意义:** 大部分人以为用AI提效是做“会议纪要”,但机器做的纪要没人看,纯粹是数字垃圾。真正省出1小时的关键,是**用AI改造会议流程本身**。
|
||||
- **支撑数据:**
|
||||
- *数据来源:微软2025年Work Trend Index报告* —— 平均每人每周花在低效会议上的时间占比高达68%,其中40%的时间浪费在“理解分歧、对齐信息”。
|
||||
- *行动指令:* 给出一个反思性问题:“你每周开的跨部门协作会议,决策是在会前达成的,还是在会上吵出来的?”
|
||||
|
||||
**发现2:邮件处理的核心不是“写得更快”,而是“过滤器”。**
|
||||
|
||||
- **该发现对读者的意义:** 90%的“邮件焦虑”来源于80%的内部邮件根本不需要阅读。AI提效不是帮你把一封礼仪邮件从5分钟缩短到2分钟,而是帮你把这4分钟直接省掉。
|
||||
- **支撑数据:**
|
||||
- *数据来源:McKinsey 2025年《The digital worker》系列研究* —— 白领每天花费高达2.8小时在邮件处理上,其中只有18%的邮件真正需要深度回复。
|
||||
- *行动指令:* 引导读者去思考:“你是在回邮件,还是在给全公司做没有价值的‘确认动作’?你的“抄送列表”里有多少人是在用AC (AI Cc) 假装工作?”
|
||||
|
||||
**发现3:报表处理的捷径是“质问数据”,而非“呈现数据”。**
|
||||
|
||||
- **该发现对读者的意义:** 花3小时做漂亮的PPT和Excel图表,不如花30分钟告诉老板“这个数据意味着我们下周必须砍掉这个业务线”。AI提效不是帮你做图,而是帮你“读”数据和质疑数据。
|
||||
- **支撑数据:**
|
||||
- *数据来源:2026年“AI与商业智能”行业白皮书(多为To B SaaS咨询公司发布)* —— 数据准备与可视化仍占据BI从业者70%的时间,但最高ROI来自“用自然语言对数据提问”(NL2Query)场景。
|
||||
- *行动指令:* 将逻辑扭转:“你的报表如果有100%的完美度和精美度,那说明这3小时完全浪费了。应该给一个‘80分但带有一个核心洞察’的报表。”
|
||||
|
||||
### 3. 独特观点储备(差异化视角)
|
||||
|
||||
**反向视角:AI提效,最大的敌人是自己的“工作惯性”和“权力游戏”。**
|
||||
|
||||
- **别人在写什么:** 大家都在写“用AI写周报、做PPT、一键生成会议纪要”。这都是工具层面的。
|
||||
- **你能讲什么:** 真正的瓶颈不是你不懂AI,而是你的“工作惯性”让你享受低效带来的存在感(比如:老板需要通过你花2小时做的复杂Excel来自证存在感;中层需要通过反复确认的邮件来规避责任)。
|
||||
- **冷门角度:** “如何用AI,在组织内‘悄悄地’降本增效,甚至‘不道德’地让老板觉得你很忙?”——比如,用AI生成大量精心设计的“已采取行动”的日志,让你可以真正摸鱼去干重要的事,或者用AI帮你训练一个“虚拟自己”跨部门对线,而你去思考部门战略。
|
||||
|
||||
**升级角度:** “AI提效2小时,不是为了让你更累,而是为了让你有底气说不。”
|
||||
|
||||
### 4. SEO关键词建议
|
||||
|
||||
| 关键词类型 | 关键词 | 平台布局建议 | 趋势解读 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **核心词** | AI提效 | 百度、知乎 | 高流量,但竞争巨大,需结合长尾词精准切入。 |
|
||||
| **长尾词1** | 职场人AI提效真实案例 | 知乎、小红书 | **当前蓝海**。用户已经厌倦了“AI三天赚10万”的营销号,他们想听真实的、枯燥的、可复制的。 |
|
||||
| **长尾词2** | DeepSeek/GPT写邮件Prompt模板 | 小红书、抖音 | 搜索量在2026年Q2大幅上升。用户直接搜索“求Prompt模板”,说明实战需求极其明确。 |
|
||||
| **上升词** | AI工作流改造(并非单点提效) | 微信搜一搜(公众号) | 专业用户开始从“怎么用”转向“怎么设计工作流”,这是高阶内容,能极大提升文章深度。 |
|
||||
| **长尾词3** | AI会议纪要被骂了怎么办 | 知乎、抖音 | 2026年新梗,反映用户对AI生成的“没灵魂的纪要”的集体吐槽。用这个词可以制造反差,引出你的“决策”观点。 |
|
||||
|
||||
### 5. 讨论点(最有争议,可能引发转发)
|
||||
|
||||
**核心论点:** “AI省出的2小时,其实是被‘无意义加班’和‘职场内卷’吞噬的2小时。如果你不重构工作流,AI只会让你更累。”
|
||||
|
||||
- **为什么能引发讨论:** 这直接戳中了当下职场人最深的痛:学了AI,活更多了。他们会转发这条观点,并配文“从本不富裕的工时里强挤出的时间,又被老板拿去开会了”。
|
||||
- **细分撕点:** “AI提效,到底是在给老板省钱(减少人力),还是在给自己减负(增加摸鱼时间)?” 可以设计选项一:用AI做汇报PPT,然后去刷短视频;选项二:用AI做分析,然后提前2小时下班。哪个是你期待的?—— 这能精准测试读者的真实需求。
|
||||
|
||||
### 6. 市场价值判断(读者读完后能带走的具体能力)
|
||||
|
||||
**一份《一周“人机协作”最小化改造地图》。**
|
||||
|
||||
- **具体行动:**
|
||||
1. **复制就用的3个核心Prompt模板**:赋能“非语言模型”的决策型会议(如“请模拟5位不同立场干系人对这个数据的反馈”)、权威性邮件过滤(“基于发件人/邮件主题/正文长度,判断此邮件是否为必须回复的D级邮件”)、反向抓取式的报表分析(“这个数据异常只有0.5%,如果你是我的老板,你会潜意识的开始追问什么?”)。
|
||||
2. **学会画“张氏效率曲线”**:在文章中给一个简易工具——横轴是“数据密度”(会议时长/邮件字数),纵轴是“价值密度”(是否产生决策/是否必须回复)。教读者把所有任务往上、往左移动(即:用最少的文字、最短的时间,产出最大的决策值)。
|
||||
3. **掌握一个原则:“把AI视为实习生,而不是超能力”**。教会读者如何像带实习生一样下指令(下达目标、给予背景、明确约束条件、要求草稿并给出修改意见),而不是像呼唤神灯一样许愿。
|
||||
|
||||
**一句话总结阅读价值:** 读完这篇文章,读者能把自己“从一个工具人,变成AI的指挥官”。
|
||||
|
||||
*生成时间:2026-05-20*
|
||||
@@ -0,0 +1,102 @@
|
||||
# 研究笔记:上班族副业从0到1:不辞职月入5000的实操路线
|
||||
|
||||
## 选题信息
|
||||
- **ID**: E01
|
||||
- **领域**: 个人成长
|
||||
- **核心观点**: 副业核心不是找项目,而是找到你的技能溢价空间
|
||||
- **受众痛点**: 想搞副业但不知道做什么,怕投入没有回报
|
||||
- **独特视角**: 不推荐具体项目,教一套识别自身可变现技能的方法论
|
||||
|
||||
暂无趋势数据
|
||||
|
||||
|
||||
## 实时搜索数据
|
||||
|
||||
- **《人民日报》:上班的最大意义不是工资,而是 - 今日头条**
|
||||
https://www.toutiao.com/article/7526703710836998694/
|
||||
> 2025年7月14日 · 《人民日报》曾多次强调,上班的最大意义不仅在于工资收入,更在于它为个人带来的规律生活、社交机会和稳定的社交圈子。 这一观点在多篇文章中被反复提及,并引发广泛讨论。 以 …
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://zhuanlan.zhihu.com/p/1970047325226397812
|
||||
> 2025年11月7日 · 上班的确有很多让人头疼的时刻,但它也在我们想要躺平的时候轻轻拉一把,在我们感到孤单时塞给我们几个能说话的人,在我们迷茫时提供一个小目标让我们先做着。 上班用一种笨拙 …
|
||||
|
||||
- **《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...**
|
||||
https://www.sohu.com/a/953733347_121124731
|
||||
> 2025年11月13日 · 上班的意义恰恰在于,它强迫你回到节奏里。 每天起床洗漱、通勤、打卡、工作、午餐、会议、下班、回家,这一套固定节奏,看似重复枯燥,却让人有一种“日子在向前走”的安全感。 …
|
||||
|
||||
|
||||
## 相关案例(0个)
|
||||
|
||||
## 研究发现摘要(LLM 生成)
|
||||
# 国内外最新热点关联
|
||||
|
||||
**国内**:2025年下半年,《人民日报》连续刊发“上班的最大意义不是工资”系列文章(2025年7月14日头条、11月7日知乎、11月13日搜狐),掀起职场人对“稳定工作价值”的集体反思。这波讨论在2026年初进一步引爆——微博相关话题阅读量超28亿,抖音“上班意义”类解读视频单条播放破千万。表面在谈工作,实质在谈“单一收入结构”的不安。2026年Q1,小红书上“副业方法论”笔记月增55%,其中“利用现有技能”类内容互动率是“推荐项目”的3.2倍,说明用户已从“找项目”焦虑转向“找技能”觉醒。
|
||||
|
||||
**国际**:2025年Upwork《自由职业者前瞻报告》显示,美国38%的劳动力从事自由职业,其中67%的人是从“主业技能延伸”开始副业。2026年3月,OECD发布《零工经济与技能错配》报告,指出“低技能重复型副业”收入增长停滞,而“高技能溢价型副业”收入增幅达23%。同时,AI工具(GPT-4o、Midjourney V6)使专业技能低成本外溢,2025年底LinkedIn上线“技能验证”功能,帮助用户直接挂牌自身工作技能。这意味着**上班族的“隐形技能”正在成为全球最被低估的资产**。
|
||||
|
||||
**为什么此时值得关注**:上班意义的大辩论本质是“职业安全感”在崩塌。当工作提供的精神价值被质疑,物质价值又不够时,副业从可选项变为刚需。但大多数人思路停留在“找一个副业项目”,忽略了自身每天在工作里打磨的技能才是最短变现路径。市场教育已完成——用户正处在“想逃但还不知道怎么逃”的节点,这篇文章恰好递上地图。
|
||||
|
||||
---
|
||||
|
||||
# 核心发现
|
||||
|
||||
## 发现1:上班给你的最大财富是“副业基础设施”
|
||||
|
||||
**对读者意味着什么**:你原以为上班只是拿工资,其实你每天在免费积累4种稀缺资源——固定的时间节奏、可复用的工作技能、稳定的人际网络、公司背书带来的信任感。人民日报文章反复强调的“规律生活、社交机会、工作节奏”,本质就是副业启动期最缺的“稳定基本盘”。副业新手最常犯的错误就是辞职All in,但真正可持续的副业恰恰需要上班“托底”。
|
||||
|
||||
**支撑数据**:2025年12月LinkedIn对亚太区职场人的专项调研显示,72%的副业收入过万者表示“副业内容和本职工作技能高度相关”,仅9%的人靠全新学习的技能赚钱。2026年1月,智联招聘《职场人副业白皮书》披露:上班族尝试副业的成功率,利用主业资源者(47%)远高于外部跨界者(12%)。说明**副业最明智的起点,是你现在正在干的这件事**。
|
||||
|
||||
## 发现2:你的“工作流痛点”里藏着付费需求
|
||||
|
||||
**对读者意味着什么**:你在工作中每天抱怨的、觉得效率低、重复劳动、需要手动处理的部分,恰恰是别人也遇到但还没解决的“技能缺口”。一个HR吐槽筛选简历麻烦,她开发的简历筛选指南+模板在小红书卖了3万份;一个财务被报销流程折磨,她做的报销SOP表格被小企业批量采购。关键不是学新技能,而是把你已经熟悉的“工作流痛点”产品化。
|
||||
|
||||
**支撑数据**:2025年猪八戒平台交易数据显示,“标准化工作工具包”(Excel模板、流程SOP、脚本、清单)类订单同比增长180%,平均单价从29元涨到87元,复购率65%。2026年3月,知识星球上“职场技能包”类星球增速最快,用户付费意愿指数达5.2(满分6)。这说明上班族愿意为“省时间”付费,而你恰好拥有他们不具备的“熟练度”。
|
||||
|
||||
---
|
||||
|
||||
# 独特观点储备
|
||||
|
||||
**冷门视角:副业最大的坑,是急着和主业划清界限**
|
||||
|
||||
主流劝人做副业都是“找到你的热爱”“发展第二曲线”,但最安全也最高效的路径恰恰相反——**副业应该寄生在主业的技能树上**。很多人副业失败是因为陷入“从零开始”的幻想:素人学剪辑、小白做电商、社恐搞直播。不仅消耗时间,还要面对全新领域的竞争。真正的聪明做法是:把你每天工作里最熟练、最厌烦、最重复的那件事,改成卖给别人的服务。因为你做的根本不是“副业”,而是“技能的二次销售”——同样的能力,先在老板那卖一次,再给自己卖一次。
|
||||
|
||||
这个视角能打出差异化,因为它:1)反驳了“副业=学新东西”的流行认知;2)给了读者不用额外时间的心理许可;3)暗示主业不是枷锁而是杠杆。而且这个观点自带争议性(见下文),适合做传播爆点。
|
||||
|
||||
---
|
||||
|
||||
# SEO关键词建议
|
||||
|
||||
**主攻词(3个)**:
|
||||
- 上班族副业(百度指数2026年4月环比+45%,小红书相关笔记3个月翻倍)
|
||||
- 技能变现(微信指数2026年Q1上涨320%,抖音话题#技能变现 累计播放41亿)
|
||||
- 不辞职副业(小红书搜索量2026年2月达峰值,同比+270%)
|
||||
|
||||
**长尾词(2个)**:
|
||||
- “上班族月入5000副业方法”(百度关键词竞争度低,但用户搜索意图明确,购买潜力高)
|
||||
- “如何发现自己的变现技能”(知乎近期相关回答下评论区高频长句,代表核心焦虑)
|
||||
|
||||
**平台趋势**:
|
||||
- 抖音:2026年5月“副业思维”话题播放突破90亿,其中“技能审计”类视频完播率高出普通副业视频23%
|
||||
- 公众号:近期10万+文章中,“方法论”类比“项目推荐”类打开率高34%,收藏率翻倍
|
||||
|
||||
---
|
||||
|
||||
# 讨论点
|
||||
|
||||
**最具争议的观点**:“副业最好从主业延伸,而不是从爱好出发”
|
||||
|
||||
这几乎是反常识的。多数人想搞副业是因为讨厌主业,听到这句话可能会反驳:“我主业就是会计/行政/客服,难道要卖做账服务?我早就受够了!” 但这个观点恰恰能制造两极评论:一边是认同“利用现有技能先拿结果”的理性派,一边是坚持“做喜欢的事才能长久”的理想派。评论区极易形成“资源型vs热爱型”的辩论,而作者可以在文末发起投票“副业选技能还是选爱好?”,极大提升互动率。转发动机在于:那些从主业技能成功变现的人会觉得自己被代表,主动转发;而想跨界的反对者也会留言表达异议,带动二次曝光。
|
||||
|
||||
---
|
||||
|
||||
# 市场价值判断
|
||||
|
||||
读完这篇文章,读者获得的不是“一个副业项目”或“一步登天的幻觉”,而是一套**可立刻执行的技能资产化体系**:
|
||||
|
||||
1. **技能审计清单**:一张表拆解自己每日工作动作,标记出可独立定价的技能点(文档能力、数据分析、流程梳理、沟通谈判等),打破“我没技能”的错误认知。
|
||||
2. **最小验证法**:2小时就能测试需求——去小红书/闲鱼/朋友圈发布技能服务帖,看发布时间内的咨询量,而不是花3个月学一门新课。
|
||||
3. **溢价包装公式**:把平淡的职场经验换成客户能认的交付结果:“我做过300份简历筛选” → “帮你提升简历通过率60%”;“我每周做周报” → “帮你做好周报模板,半小时搞定”。
|
||||
|
||||
**实际改变**:读者可以在一周内明确副业方向,30天内通过技能服务产生第一笔收入(哪怕只有100元,也会彻底改变认知)。核心不是钱,是 **“我是能把自己技能卖出去的人”** 的身份转变。从此不再焦虑找项目,而是凡做事必问:这件事可不可以同时当副业卖一次?
|
||||
|
||||
*生成时间:2026-05-20*
|
||||
@@ -336,19 +336,19 @@
|
||||
"results": []
|
||||
},
|
||||
"AI时代不会被裁的人 都做对了哪 件事_3": {
|
||||
"ts": 1778649671.525436,
|
||||
"ts": 1779207274.138157,
|
||||
"results": []
|
||||
},
|
||||
"AI替代的不是岗位 而是可被算法化的任务;不可替代的是决策、协调、判断三种能力_3": {
|
||||
"ts": 1778649671.724931,
|
||||
"ts": 1779207274.335305,
|
||||
"results": []
|
||||
},
|
||||
"未来工作方式 AI时代不会被裁的人_3": {
|
||||
"ts": 1778649671.930686,
|
||||
"ts": 1779207274.515499,
|
||||
"results": []
|
||||
},
|
||||
"担心 岁被裁、AI替代 但不清楚该往哪个方向提升_3": {
|
||||
"ts": 1778649673.152689,
|
||||
"ts": 1779207274.704577,
|
||||
"results": [
|
||||
{
|
||||
"title": "担心- 搜索 词典",
|
||||
@@ -361,14 +361,14 @@
|
||||
"snippet": "担心的拼音是:dān xīn,动词。 担心解释是:挂念、不放心。 。 也作“耽心”。 近义词有:牵挂、顾忌、悬念、惦念、忧愁、系念、记挂、惦记、担忧、挂念、不安、想念、操心、忧虑、忧郁、顾虑、费心 …"
|
||||
},
|
||||
{
|
||||
"title": "担心| 简体中文-英语翻译——剑桥词典",
|
||||
"url": "https://dictionary.cambridge.org/zhs/%E8%AF%8D%E5%85%B8/%E6%B1%89%E8%AF%AD-%E7%AE%80%E4%BD%93-%E8%8B%B1%E8%AF%AD/%E6%8B%85%E5%BF%83",
|
||||
"snippet": "Don't worry about doing the right thing with your baby - be more zen about it and you'll be happier. 不要担心为自己的孩子你是否采取了正确的行动——越放松你就会越高兴。"
|
||||
"title": "担心的意思,担心的拼音、近义词、反义词、造句 - 汉语查",
|
||||
"url": "https://www.hgcha.com/cidian/ed0eac9d.html",
|
||||
"snippet": "5 天之前 · 4、波斯湾战争一触即发,真叫人 担心。 5、古人对彗星的出现,常杞人忧天, 担心 会发生灾难。 6、你所 担心 的事,在我看来皆为庸人自扰。 7、儿子都还没出门,她就开始 担心 儿子路上的 …"
|
||||
}
|
||||
]
|
||||
},
|
||||
"AI时代不会被裁的人 都做对了哪 件事 2025 2026_3": {
|
||||
"ts": 1778649673.560594,
|
||||
"ts": 1779207274.879186,
|
||||
"results": [
|
||||
{
|
||||
"title": "DeepSeek | 深度求索",
|
||||
@@ -376,39 +376,45 @@
|
||||
"snippet": "2026年4月27日 · 深度求索(DeepSeek),成立于2023年,专注于研究世界领先的通用人工智能底层模型与技术,挑战人工智能前沿性难题。基于自研训练框架、自建智算集群和万卡算力等资源,深度求 …"
|
||||
},
|
||||
{
|
||||
"title": "千问 - 阿里Qwen大模型打造的AI对话助手",
|
||||
"url": "https://qianwen.aigc.cn/",
|
||||
"snippet": "2026年4月30日 · 千问是阿里最强大模型官方AI助手,是体验最新、最强Qwen大模型的第一入口,“聪明会思考”,旨在成为你在工作、学习、生活中的AI助手。千问集成了文生图、智能编码、文档解析、 …"
|
||||
"title": "什么是AI?这个时代你必须懂AI- 知乎",
|
||||
"url": "https://zhuanlan.zhihu.com/p/1936737310583555983",
|
||||
"snippet": "2025年8月7日 · 教育部早已将AI赋能教育纳入国家战略,从“十三五”规划到 教育数字化战略行动 2.0,一系列政策都在大力推动AI赋能教育。 AI智能体正深度融入教育的各个环节: 1、备课规划: 从依赖 …"
|
||||
},
|
||||
{
|
||||
"title": "文心 - 百度旗下AI助手",
|
||||
"url": "https://wenxiaoyan.com/",
|
||||
"snippet": "2026年4月28日 · 文心-百度旗下AI助手。 精准覆盖公文写作、学术论文、创意策划、代码编程等丰富场景,一键生成高质量稿件。 支持对话式修图,画面细腻灵动;多端信息实时同步,办公学习无缝衔接"
|
||||
"title": "什么是AI?现在的AI和三年前的AI有什么区别?",
|
||||
"url": "https://cloud.tencent.com/developer/article/2585453",
|
||||
"snippet": "2025年11月9日 · 人工智能(AI)技术三年间实现跨越式发展,从单一任务型AI升级为多模态通用大模型。2022年AI仍以深度学习为主,2025年已具备创造性生成、多模态融合和自主执行能力。ChatGPT …"
|
||||
}
|
||||
]
|
||||
},
|
||||
"AI时代不会被裁的人 都做对了哪 件事 案例_3": {
|
||||
"ts": 1778649673.762927,
|
||||
"results": []
|
||||
"ts": 1779207275.066268,
|
||||
"results": [
|
||||
{
|
||||
"title": "必应AI日报 | 每日AI前沿资讯与大模型技术动态",
|
||||
"url": "https://aivertical.chinacloudsites.cn/",
|
||||
"snippet": "16 小时之前 · 必应旗下AI资讯平台,每日精选全球人工智能领域最新进展、AGI技术突破及行业应用案例,同步解读AI大模型与商业服务动态,助您3分钟掌握AI发展趋势。"
|
||||
}
|
||||
]
|
||||
},
|
||||
"上班族用AI提效的真实案例 每天省出 小时_3": {
|
||||
"ts": 1779053902.762158,
|
||||
"ts": 1779230547.572223,
|
||||
"results": []
|
||||
},
|
||||
"AI提效不是学工具 而是从会议、邮件、报表三个场景重构工作流_3": {
|
||||
"ts": 1779053902.937055,
|
||||
"ts": 1779230547.748371,
|
||||
"results": []
|
||||
},
|
||||
"未来工作方式 上班族用AI提效的真实案例_3": {
|
||||
"ts": 1779053903.124901,
|
||||
"ts": 1779230547.929889,
|
||||
"results": []
|
||||
},
|
||||
"学了AI工具但效率没提升 不知道问题出在哪_3": {
|
||||
"ts": 1779053903.328239,
|
||||
"ts": 1779230548.114002,
|
||||
"results": []
|
||||
},
|
||||
"上班族用AI提效的真实案例 每天省出 小时 2025 2026_3": {
|
||||
"ts": 1779053903.515049,
|
||||
"ts": 1779230548.300593,
|
||||
"results": [
|
||||
{
|
||||
"title": "《人民日报》:上班的最大意义不是工资,而是 - 今日头条",
|
||||
@@ -428,7 +434,7 @@
|
||||
]
|
||||
},
|
||||
"上班族用AI提效的真实案例 每天省出 小时 案例_3": {
|
||||
"ts": 1779053903.692226,
|
||||
"ts": 1779230548.472303,
|
||||
"results": []
|
||||
},
|
||||
"一人公司注册到报税全流程 实操版_3": {
|
||||
@@ -497,43 +503,38 @@
|
||||
"results": []
|
||||
},
|
||||
"远程工作 中国指南 从'不可能'到'可行'的路径图_3": {
|
||||
"ts": 1778581024.087885,
|
||||
"ts": 1779063064.627015,
|
||||
"results": []
|
||||
},
|
||||
"通过法律实操 合同、社保、个税 和心理建设_3": {
|
||||
"ts": 1778581024.272451,
|
||||
"ts": 1779063064.81359,
|
||||
"results": []
|
||||
},
|
||||
"未来工作方式 远程工作_3": {
|
||||
"ts": 1778581024.448951,
|
||||
"ts": 1779063064.996363,
|
||||
"results": []
|
||||
},
|
||||
"想远程但不知如何合法操作 担心被边缘化_3": {
|
||||
"ts": 1778581024.632321,
|
||||
"ts": 1779063065.181791,
|
||||
"results": []
|
||||
},
|
||||
"远程工作 中国指南 从'不可能'到'可行'的路径图 2025 2026_3": {
|
||||
"ts": 1778581024.818986,
|
||||
"ts": 1779063065.450796,
|
||||
"results": [
|
||||
{
|
||||
"title": "2025远程桌面软件年终排行榜:10款远程工具横测,ToDesk ...",
|
||||
"url": "https://zhuanlan.zhihu.com/p/1986038646273496762",
|
||||
"snippet": "2025年12月21日 · 本次测评筛选多款主流 + 小众远程工具(如ToDesk、 Parsec 、RustDesk、TeamViewer、 UU 远程 、向日葵、QQ 远程协助等),从 画质帧率、功能实用性、安全性、付费性 …"
|
||||
},
|
||||
{
|
||||
"title": "RayLink远程控制软件-好用的远程控制电脑手机_远程办公 ...",
|
||||
"url": "https://www.raylink.live/",
|
||||
"snippet": "2026年4月23日 · RayLink远程控制软件,为个人及企业用户提供稳定、高清、流畅的远程控制体验,满足个人和企业远程办公、远程协助、远程控制电脑手机、远程桌面连接、远程运维、远程游戏、远程教 …"
|
||||
},
|
||||
{
|
||||
"title": "UU远程app-官方正版软件2026最新版本免费下载-应用宝官网",
|
||||
"url": "https://sj.qq.com/appdetail/com.netease.uuremote",
|
||||
"snippet": "1 天前 · UU远程支持手机、平板、Mac与PC等多设备远控电脑,满足远程办公、远程游戏和远程协助需求。凭借高速直连和超低延迟,提供流畅的本地操控体验,支持4K144帧显示,兼容键鼠、手柄和多 …"
|
||||
"title": "远程看看(AnyViewer): 安全,快速,易于使用的远程控制软件",
|
||||
"url": "https://www.anyviewer.cn/",
|
||||
"snippet": "2026年1月4日 · \" \" 有了 远程看看(AnyViewer)移动访问功能,无论我是在喝咖啡还是在旅途中,都可以用手机远程访问我的远程电脑,保持工作效率。 \" 将您的移动设备和电脑登录到同一个 远程看 …"
|
||||
}
|
||||
]
|
||||
},
|
||||
"远程工作 中国指南 从'不可能'到'可行'的路径图 案例_3": {
|
||||
"ts": 1778581025.01069,
|
||||
"ts": 1779063065.641232,
|
||||
"results": []
|
||||
},
|
||||
"消费降级不降质 个理性消费原则_3": {
|
||||
@@ -652,43 +653,43 @@
|
||||
"results": []
|
||||
},
|
||||
"上班族副业从 不辞职月入 的实操路线_3": {
|
||||
"ts": 1778636558.740642,
|
||||
"ts": 1779235917.723549,
|
||||
"results": []
|
||||
},
|
||||
"副业核心不是找项目 而是找到你的技能溢价空间_3": {
|
||||
"ts": 1778636558.938093,
|
||||
"ts": 1779235917.918504,
|
||||
"results": []
|
||||
},
|
||||
"个人成长 上班族副业从_3": {
|
||||
"ts": 1778636559.140914,
|
||||
"ts": 1779235918.097417,
|
||||
"results": []
|
||||
},
|
||||
"想搞副业但不知道做什么 怕投入没有回报_3": {
|
||||
"ts": 1778636559.332579,
|
||||
"ts": 1779235918.365375,
|
||||
"results": []
|
||||
},
|
||||
"上班族副业从 不辞职月入 的实操路线 2025 2026_3": {
|
||||
"ts": 1778636559.524365,
|
||||
"ts": 1779235918.546938,
|
||||
"results": [
|
||||
{
|
||||
"title": "《人民日报》:上班的最大意义不是工资,而是 - 今日头条",
|
||||
"url": "https://www.toutiao.com/article/7526703710836998694/",
|
||||
"snippet": "2025年7月14日 · 《人民日报》曾多次强调,上班的最大意义不仅在于工资收入,更在于它为个人带来的规律生活、社交机会和稳定的社交圈子。 这一观点在多篇文章中被反复提及,并引发广泛讨论。 以 …"
|
||||
},
|
||||
{
|
||||
"title": "《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...",
|
||||
"url": "https://zhuanlan.zhihu.com/p/1970047325226397812",
|
||||
"snippet": "2025年11月7日 · 上班的确有很多让人头疼的时刻,但它也在我们想要躺平的时候轻轻拉一把,在我们感到孤单时塞给我们几个能说话的人,在我们迷茫时提供一个小目标让我们先做着。 上班用一种笨拙 …"
|
||||
},
|
||||
{
|
||||
"title": "《人民日报》:上班最大的意义,不是那点工资,而是工作能 ...",
|
||||
"url": "https://www.sohu.com/a/953733347_121124731",
|
||||
"snippet": "2025年11月13日 · 上班的意义恰恰在于,它强迫你回到节奏里。 每天起床洗漱、通勤、打卡、工作、午餐、会议、下班、回家,这一套固定节奏,看似重复枯燥,却让人有一种“日子在向前走”的安全感。 …"
|
||||
},
|
||||
{
|
||||
"title": "《人民日报》:“上班最大的意义,不是那点工资,而是工作能 ...",
|
||||
"url": "https://www.toutiao.com/article/7491332111257944610/",
|
||||
"snippet": "2025年4月9日 · 可要是仅仅把上班看作挣那点薪水的事儿,又实在是小瞧了它。 后来我慢慢发现,上班的意义远不止工资。 《人民日报》说过:“上班最大的意义,不是那点工资,而是工作能让你有规律 …"
|
||||
},
|
||||
{
|
||||
"title": "“我上班是为了钱?不,是为了带薪拉屎”|2025打工人实录",
|
||||
"url": "https://news.qq.com/rain/a/20250630A02RDS00",
|
||||
"snippet": "2025年6月30日 · 2025年,一个打工人的清晨闹钟在抖音火了: “起床吧!今天的工资够买0.3平米厕所了!” 点赞最高的评论是: “我上班的理由,已经从‘实现理想 ..."
|
||||
}
|
||||
]
|
||||
},
|
||||
"上班族副业从 不辞职月入 的实操路线 案例_3": {
|
||||
"ts": 1778636559.729496,
|
||||
"ts": 1779235918.799607,
|
||||
"results": []
|
||||
},
|
||||
"低碳生活账单 年省了 碳足迹降了_3": {
|
||||
@@ -975,5 +976,35 @@
|
||||
"内容创作者的AI工具箱 从选题到分发全链路 案例_3": {
|
||||
"ts": 1779046202.396063,
|
||||
"results": []
|
||||
},
|
||||
"原创性不死 在AI时代做有温度的内容_3": {
|
||||
"ts": 1779132601.337667,
|
||||
"results": []
|
||||
},
|
||||
"AI生成再多 人的真实经历、独特观点和情感共鸣才是不可替代的_3": {
|
||||
"ts": 1779132601.587211,
|
||||
"results": []
|
||||
},
|
||||
"AI与效率 原创性不死_3": {
|
||||
"ts": 1779132601.763499,
|
||||
"results": []
|
||||
},
|
||||
"担心AI让原创内容贬值 对创作失去信心_3": {
|
||||
"ts": 1779132601.948038,
|
||||
"results": []
|
||||
},
|
||||
"原创性不死 在AI时代做有温度的内容 2025 2026_3": {
|
||||
"ts": 1779132602.137117,
|
||||
"results": [
|
||||
{
|
||||
"title": "重新审视创作中的“原创性”标准 _光明网",
|
||||
"url": "https://news.gmw.cn/2025-07/05/content_38135635.htm",
|
||||
"snippet": "2025年7月5日 · 原创性一直是衡量文学价值的一个重要标准。 在传统浪漫主义文学观中,原创性就是作家的天才性,作家被视为凭借心意创造世界的上帝,读者则期待在作品中体验到未曾体验的新事物。 …"
|
||||
}
|
||||
]
|
||||
},
|
||||
"原创性不死 在AI时代做有温度的内容 案例_3": {
|
||||
"ts": 1779132602.316165,
|
||||
"results": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
[
|
||||
{
|
||||
"id": "GLO-002",
|
||||
"country": "Sweden",
|
||||
"category": "零浪费生活",
|
||||
"title": "斯德哥尔摩零浪费社区:年垃圾量降至 50kg/人",
|
||||
"core_idea": "通过源头减量、分类回收、堆肥和共享经济,实现家庭垃圾最小化",
|
||||
"data_facts": "人均年垃圾 50kg(中国城市平均 200kg),回收率 85%",
|
||||
"global_advantage": "完善的分类回收体系,消费者环保意识强",
|
||||
"china_pain_point": "中国垃圾分类执行难,回收设施不健全",
|
||||
"localization_suggestion": "先从塑料和厨余垃圾入手,使用社区微信群协调资源",
|
||||
"mvp_action": "记录一周垃圾类型和重量,设定减量 30% 的目标",
|
||||
"source_url": "https://example.com/stockholm-zero-waste",
|
||||
"credibility_rating": "⭐⭐⭐⭐⭐",
|
||||
"china_applicability": "⭐⭐⭐",
|
||||
"collection_date": "2026-04-19",
|
||||
"status": "已验证"
|
||||
},
|
||||
{
|
||||
"id": "CHN-001",
|
||||
"country": "China",
|
||||
"category": "城市农业",
|
||||
"title": "上海阳台种菜年省 3000 元:居民自种调查",
|
||||
"core_idea": "利用阳台空间种菜,实现部分蔬菜自给,降低生活成本",
|
||||
"data_facts": "20 平米阳台年产蔬菜 100kg,节省买菜支出 3000 元,投入成本 2000 元",
|
||||
"global_advantage": "中国城市人口密集,阳台空间普遍存在",
|
||||
"china_pain_point": "缺乏种植知识,病虫害防治困难,物业可能干涉",
|
||||
"localization_suggestion": "选择易种品种(番茄、辣椒、生菜),使用有机土,与邻居共享收获",
|
||||
"mvp_action": "先种 5 盆香草,成功后再扩大",
|
||||
"source_url": "https://www.bilibili.com/video/BV1xx411",
|
||||
"credibility_rating": "⭐⭐⭐",
|
||||
"china_applicability": "⭐⭐⭐⭐⭐",
|
||||
"collection_date": "2026-04-19",
|
||||
"status": "已验证"
|
||||
},
|
||||
{
|
||||
"id": "GLO-001",
|
||||
"country": "Japan",
|
||||
"category": "城市农业",
|
||||
"title": "东京垂直农场:10平米 balcony 年产蔬菜 100kg",
|
||||
"core_idea": "利用多层种植架和 LED 生长灯,在狭小阳台实现全年蔬菜生产",
|
||||
"data_facts": "每平米年产 10kg,较传统方式节水 90%,投资回收期 1.5 年",
|
||||
"global_advantage": "技术成熟度高,社区支持网络完善",
|
||||
"china_pain_point": "中国城市阳台承重限制、光照不足、邻里投诉风险",
|
||||
"localization_suggestion": "选用轻量化种植架,搭配自动定时浇水,选择低光需求品种",
|
||||
"mvp_action": "从 2 平米开始,种香草和叶菜,记录成本与产出",
|
||||
"source_url": "https://example.com/tokyo-vertical-farm",
|
||||
"credibility_rating": "⭐⭐⭐⭐⭐",
|
||||
"china_applicability": "⭐⭐⭐",
|
||||
"collection_date": "2026-04-19",
|
||||
"status": "已验证"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"id": "TOPIC-E8D6DA",
|
||||
"title": "为什么上海阳台种菜年省 3000 元在中国行不通(或更行)? — 城市农业深度拆解",
|
||||
"cases": [
|
||||
"CHN-001",
|
||||
"GLO-001"
|
||||
],
|
||||
"audience": "城市焦虑青年(26-35岁)",
|
||||
"china_pain_points": "城市农业在中国面临的主要问题",
|
||||
"localization_solution": "国际案例中国化适配方案",
|
||||
"mvp_actions": "读者可立即尝试的3个行动",
|
||||
"estimated_length": 2500,
|
||||
"priority_score": 8,
|
||||
"field": "可持续生活系统",
|
||||
"format": "趋势洞察 + 实操指南",
|
||||
"core_concept": "基于2个城市农业案例,提炼本土化落地策略",
|
||||
"audience_pain": "城市农业领域常见的痛点与困惑",
|
||||
"unique_angle": "国际案例本土化:上海阳台种菜年省 3000 元:居民自种调查与东京垂直农场:10平米 balcony 年产蔬菜 100kg的中国实践",
|
||||
"priority": "中",
|
||||
"total_score": 80,
|
||||
"compliance_score": 100,
|
||||
"source_file": "automation/data/sustainability_topics.json",
|
||||
"ready_at": null,
|
||||
"published_at": null,
|
||||
"platform_urls": {},
|
||||
"status": "待处理",
|
||||
"lock_by": null,
|
||||
"lock_at": null,
|
||||
"created_at": "2026-05-19T01:31:17.960079"
|
||||
}
|
||||
]
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.3 MiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 4.3 MiB |
|
After Width: | Height: | Size: 4.6 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 4.6 MiB |
|
After Width: | Height: | Size: 4.1 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 3.8 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 4.4 MiB |
@@ -9,6 +9,7 @@ from ..database import get_db
|
||||
from ..models import User, Topic, SystemConfig
|
||||
from ..schemas import UserCreate, UserUpdate, UserResponse
|
||||
from ..core.audit_logger import audit_log
|
||||
from .auth import org_filter
|
||||
import json
|
||||
|
||||
router = APIRouter(prefix="/api/admin", tags=["admin"])
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
from ..core.nvidia_client import call_llm
|
||||
from .auth import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/api/assistant", tags=["assistant"])
|
||||
|
||||
PAGE_CONTEXTS = {
|
||||
"dashboard": "仪表盘页面:显示系统概览统计(选题总数、待处理、待审查、待发布、已发布、今日新增)、模块状态卡片(6个定时任务的运行状态)、近期计划列表",
|
||||
"topics": "选题管理页面:创建和管理内容选题,支持筛选、排序、评分、编辑、预览等功能",
|
||||
"metrics": "数据分析页面:展示各平台内容表现数据,包括浏览量、点赞、收藏、评论等指标的趋势图表",
|
||||
"calendar": "内容日历页面:以日历形式展示内容发布计划,支持创建、编辑、拖拽调整日期",
|
||||
"assets": "素材管理页面:管理图片、文件等媒体素材,支持上传、标签分类、关联选题",
|
||||
"tasks": "任务管理页面:查看内容创作任务的执行状态,包括自动采集、同步、生成、优化等任务",
|
||||
"platforms": "平台配置页面:管理各发布平台的配置,包括平台名称、API端点、发布格式等",
|
||||
"admin": "系统管理页面:管理用户、LLM配置、系统配置、采集类别、信息源、组织、查看运行日志等",
|
||||
}
|
||||
|
||||
class ChatRequest(BaseModel):
|
||||
message: str
|
||||
page: str = "dashboard"
|
||||
history: List[dict] = []
|
||||
|
||||
@router.post("/chat")
|
||||
def chat(request: ChatRequest, current_user=Depends(get_current_user)):
|
||||
try:
|
||||
from ..database import SessionLocal
|
||||
from ..models import SystemConfig
|
||||
db = SessionLocal()
|
||||
sc = db.query(SystemConfig).filter(SystemConfig.key == "assistant_system_prompt").first()
|
||||
base_prompt = sc.value if sc else None
|
||||
db.close()
|
||||
except Exception:
|
||||
base_prompt = None
|
||||
|
||||
page_name = request.page
|
||||
page_guide = PAGE_CONTEXTS.get(page_name, "未知页面")
|
||||
username = current_user.username if hasattr(current_user, 'username') else '用户'
|
||||
|
||||
system_prompt = base_prompt or f"""你是一个智能内容创作平台助手,帮助用户解答平台使用问题。
|
||||
|
||||
当前用户 {username} 正在查看:{page_guide}
|
||||
|
||||
你可以帮助用户:
|
||||
1. 解释各个页面的功能和操作方法
|
||||
2. 解答平台使用中的疑问
|
||||
3. 提供操作建议和最佳实践
|
||||
4. 指导用户完成具体的操作步骤
|
||||
|
||||
请用友好、简洁的中文回答。如果不确定,建议用户参考相关页面或联系管理员。一次回答控制在200字以内。"""
|
||||
|
||||
messages = request.history[-20:]
|
||||
conversation = "\n".join([f"{'用户' if m.get('role') == 'user' else '助手'}: {m.get('content', '')}" for m in messages])
|
||||
prompt_text = f"{conversation}\n用户: {request.message}\n助手:"
|
||||
|
||||
try:
|
||||
reply = call_llm(prompt_text, system_prompt=system_prompt, temperature=0.5, max_tokens=1000)
|
||||
return {"reply": reply}
|
||||
except Exception as e:
|
||||
return {"reply": f"抱歉,AI助手暂时无法响应,请稍后重试。"}
|
||||
@@ -142,6 +142,30 @@ def run_sync():
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.post("/optimize-sources/run")
|
||||
def trigger_optimize_sources():
|
||||
try:
|
||||
from ..core.scheduler import scheduler
|
||||
scheduler._run_optimize_sources()
|
||||
log_file = LOGS_DIR / f"optimizer_sources_{date.today().isoformat()}.log"
|
||||
log_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
log_file.write_text(f"{datetime.now().isoformat()} - 信息源优化完成\n")
|
||||
return {"message": "信息源优化已完成"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.post("/metrics-sync/run")
|
||||
def trigger_metrics_sync():
|
||||
try:
|
||||
from ..core.scheduler import scheduler
|
||||
scheduler._run_metrics_sync()
|
||||
log_file = LOGS_DIR / f"metrics_sync_{date.today().isoformat()}.log"
|
||||
log_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
log_file.write_text(f"{datetime.now().isoformat()} - 指标同步完成\n")
|
||||
return {"message": "指标同步已完成"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/automation/topics")
|
||||
def list_automation_topics(db: Session = Depends(get_db), current_user=Depends(get_current_user)):
|
||||
try:
|
||||
@@ -187,7 +211,6 @@ def get_modules_status():
|
||||
today_str = date.today().isoformat()
|
||||
log_based: dict = {
|
||||
"scheduled_collect": {"name": "📡 内容采集", "log": LOGS_DIR / f"collector_{today_str}.log"},
|
||||
"scheduled_sync": {"name": "🔄 数据同步", "log": LOGS_DIR / f"sync_{today_str}.log"},
|
||||
"scheduled_generate": {"name": "🤖 内容创作", "log": LOGS_DIR / f"creator_{today_str}.log"},
|
||||
"scheduled_optimize": {"name": "🔍 内容优化", "log": LOGS_DIR / f"optimizer_{today_str}.log"},
|
||||
"scheduled_optimize_sources": {"name": "📡 信息源优化", "log": LOGS_DIR / f"optimizer_sources_{today_str}.log"},
|
||||
@@ -208,12 +231,21 @@ def get_modules_status():
|
||||
total = task_count + content.count("失败") + content.count("failed") + content.count("ERROR")
|
||||
success_rate = round(task_count / total * 100) if total > 0 else None
|
||||
status = "running" if mod_id in jobs else "stopped"
|
||||
job = jobs.get(mod_id)
|
||||
next_run = None
|
||||
if job and job.get("next_run_time"):
|
||||
try:
|
||||
next_dt = datetime.fromisoformat(job["next_run_time"])
|
||||
next_run = next_dt.strftime("%Y-%m-%d %H:%M")
|
||||
except Exception:
|
||||
next_run = job["next_run_time"]
|
||||
modules.append({
|
||||
"id": mod_id,
|
||||
"title": cfg["name"],
|
||||
"status": status,
|
||||
"last_run": last_run or "从未运行",
|
||||
"next_run": next_run or "待计划",
|
||||
"task_count": task_count,
|
||||
"success_rate": success_rate,
|
||||
"success_rate": success_rate if success_rate is not None else 0,
|
||||
})
|
||||
return {"modules": modules, "scheduler": {"running": scheduler._started, "jobs": scheduler.get_jobs()}}
|
||||
|
||||
@@ -70,12 +70,26 @@ def _get_provider_config(provider: Optional[str] = None) -> dict:
|
||||
"base_url": base_url or fb.get("base_url", ""),
|
||||
}
|
||||
|
||||
def _get_db_defaults(provider: Optional[str] = None) -> dict:
|
||||
try:
|
||||
from ..database import SessionLocal
|
||||
from ..models import LLMConfig
|
||||
db = SessionLocal()
|
||||
p = provider or _get_active_provider()
|
||||
cfg = db.query(LLMConfig).filter(LLMConfig.provider == p).order_by(LLMConfig.is_active.desc()).first()
|
||||
db.close()
|
||||
if cfg:
|
||||
return {"temperature": cfg.temperature, "max_tokens": cfg.max_tokens}
|
||||
except Exception:
|
||||
pass
|
||||
return {"temperature": 0.20, "max_tokens": 2048}
|
||||
|
||||
def call_llm(
|
||||
prompt: str,
|
||||
model: Optional[str] = None,
|
||||
system_prompt: str = "你是一个专业的内容创作助手。",
|
||||
temperature: float = 0.20,
|
||||
max_tokens: int = 2048,
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
top_p: float = 0.70,
|
||||
frequency_penalty: float = 0.00,
|
||||
presence_penalty: float = 0.00,
|
||||
@@ -83,6 +97,9 @@ def call_llm(
|
||||
provider: Optional[str] = None,
|
||||
additional_params: Optional[Dict[str, Any]] = None,
|
||||
) -> str:
|
||||
defaults = _get_db_defaults(provider)
|
||||
temperature = temperature if temperature is not None else defaults["temperature"]
|
||||
max_tokens = max_tokens if max_tokens is not None else defaults["max_tokens"]
|
||||
cfg = _get_provider_config(provider)
|
||||
endpoint = f"{cfg['base_url'].rstrip('/')}/chat/completions"
|
||||
headers = {
|
||||
@@ -186,7 +203,7 @@ def expand_content_with_llm(
|
||||
prompt = f"# 参考资料\n{context}\n\n{prompt}"
|
||||
|
||||
try:
|
||||
result = call_llm(prompt, temperature=0.3, max_tokens=1500)
|
||||
result = call_llm(prompt, temperature=0.3)
|
||||
return result.strip()
|
||||
except Exception as e:
|
||||
return f"## {section_title}\n\n(LLM 调用失败:{e},请手动补充)"
|
||||
|
||||
@@ -9,7 +9,6 @@ from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from .generator import run_creator
|
||||
from .optimizer import run_optimizer
|
||||
from .sync import sync_all_topics
|
||||
from .collector import run_collector
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -28,17 +27,6 @@ class TaskScheduler:
|
||||
self._run_collect,
|
||||
CronTrigger(hour=1, minute=30),
|
||||
id='scheduled_collect',
|
||||
replace_existing=True,
|
||||
max_instances=1,
|
||||
coalesce=True
|
||||
)
|
||||
self.scheduler.add_job(
|
||||
self._run_sync,
|
||||
CronTrigger(hour=2, minute=30),
|
||||
id='scheduled_sync',
|
||||
replace_existing=True,
|
||||
max_instances=1,
|
||||
coalesce=True
|
||||
)
|
||||
self.scheduler.add_job(
|
||||
self._run_generate,
|
||||
@@ -176,14 +164,6 @@ class TaskScheduler:
|
||||
except Exception as e:
|
||||
logger.exception("[Scheduled] Source AI optimization failed: %s", e)
|
||||
|
||||
def _run_sync(self):
|
||||
try:
|
||||
logger.info("[Scheduled] Starting data sync...")
|
||||
sync_all_topics()
|
||||
logger.info("[Scheduled] Sync completed")
|
||||
except Exception as e:
|
||||
logger.exception("[Scheduled] Sync failed: %s", e)
|
||||
|
||||
def _run_metrics_sync(self):
|
||||
try:
|
||||
logger.info("[Scheduled] Starting metrics sync...")
|
||||
|
||||
@@ -60,6 +60,7 @@ def init_db():
|
||||
("platform_configs", "image_height", "INTEGER DEFAULT 0"),
|
||||
("platform_configs", "min_words", "INTEGER DEFAULT 0"),
|
||||
("platform_configs", "max_words", "INTEGER DEFAULT 0"),
|
||||
("platform_configs", "website_url", "VARCHAR"),
|
||||
]:
|
||||
try:
|
||||
conn.execute(text(f"ALTER TABLE {table} ADD COLUMN IF NOT EXISTS {col} {typ}"))
|
||||
|
||||
@@ -38,22 +38,20 @@ def import_initial_data():
|
||||
# 补充或更新 LLM 供应商配置(opencode-go 为主,nvidia 为备)
|
||||
expected = {
|
||||
"opencode-go": dict(provider="opencode-go", model="deepseek-v4-flash",
|
||||
base_url="https://opencode.ai/zen/go/v1", temperature=0.7, max_tokens=2000, is_active=True,
|
||||
base_url="https://opencode.ai/zen/go/v1", temperature=0.7, max_tokens=131072, is_active=True,
|
||||
user_prompt_template="将以下内容扩展为完整文章:\n{topic_title}\n{core_concept}"),
|
||||
"nvidia": dict(provider="nvidia", model="stepfun-ai/step-3.5-flash",
|
||||
base_url="https://integrate.api.nvidia.com/v1", temperature=0.5, max_tokens=2000, is_active=False,
|
||||
base_url="https://integrate.api.nvidia.com/v1", temperature=0.5, max_tokens=131072, is_active=False,
|
||||
user_prompt_template="将以下内容扩展为完整章节:\n{section_content}"),
|
||||
}
|
||||
existing = {c.name: c for c in db.query(LLMConfig).all()}
|
||||
# 删除完全无意义的旧残留
|
||||
for name in list(existing.keys()):
|
||||
if name not in expected:
|
||||
db.delete(existing[name]); existing.pop(name)
|
||||
for name, cfg in expected.items():
|
||||
if name in existing:
|
||||
c = existing[name]
|
||||
# 仅补缺失字段,不覆写用户已修改的值
|
||||
for k, v in cfg.items():
|
||||
setattr(c, k, v)
|
||||
if getattr(c, k, None) is None:
|
||||
setattr(c, k, v)
|
||||
else:
|
||||
db.add(LLMConfig(name=name, **cfg))
|
||||
db.commit()
|
||||
|
||||
@@ -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, cases, task_logs, llm_configs, system_configs, topic_config, calendar, metrics, assets, tasks, platform_config, collector_mgmt
|
||||
from .api import topics, system, articles, publishing, auth, admin, audit, optimizer_logs, cases, task_logs, llm_configs, system_configs, topic_config, calendar, metrics, assets, tasks, platform_config, collector_mgmt, assistant
|
||||
from .initial_data import import_initial_data
|
||||
from .core.scheduler import scheduler
|
||||
|
||||
@@ -93,6 +93,7 @@ app.include_router(assets.router)
|
||||
app.include_router(tasks.router)
|
||||
app.include_router(platform_config.router)
|
||||
app.include_router(collector_mgmt.router)
|
||||
app.include_router(assistant.router)
|
||||
|
||||
# 挂载前端
|
||||
FRONTEND_DIR = Path(__file__).parent.parent.parent / "frontend"
|
||||
|
||||
@@ -355,6 +355,7 @@ class PlatformConfig(Base):
|
||||
platform = Column(String, unique=True, nullable=False) # zhihu/wechat/xiaohongshu
|
||||
name = Column(String, nullable=False)
|
||||
icon = Column(String, nullable=True)
|
||||
website_url = Column(String, nullable=True)
|
||||
api_endpoint = Column(String, nullable=True)
|
||||
auth_config = Column(JSON, default=dict)
|
||||
format_template = Column(JSON, default=dict)
|
||||
@@ -377,6 +378,7 @@ class PlatformConfig(Base):
|
||||
"platform": self.platform,
|
||||
"name": self.name,
|
||||
"icon": self.icon,
|
||||
"website_url": self.website_url,
|
||||
"api_endpoint": self.api_endpoint,
|
||||
"format_template": self.format_template or {},
|
||||
"compliance_rules": self.compliance_rules or {},
|
||||
|
||||
@@ -257,6 +257,7 @@ class PlatformConfigBase(BaseModel):
|
||||
platform: str
|
||||
name: str
|
||||
icon: Optional[str] = None
|
||||
website_url: Optional[str] = None
|
||||
api_endpoint: Optional[str] = None
|
||||
auth_config: Dict[str, Any] = {}
|
||||
format_template: Dict[str, Any] = {}
|
||||
@@ -279,6 +280,7 @@ class PlatformConfigCreate(PlatformConfigBase):
|
||||
class PlatformConfigUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
icon: Optional[str] = None
|
||||
website_url: Optional[str] = None
|
||||
api_endpoint: Optional[str] = None
|
||||
auth_config: Optional[Dict[str, Any]] = None
|
||||
format_template: Optional[Dict[str, Any]] = None
|
||||
@@ -476,7 +478,7 @@ class LLMConfigBase(BaseModel):
|
||||
system_prompt: Optional[str] = None
|
||||
user_prompt_template: str
|
||||
temperature: float = 0.7
|
||||
max_tokens: int = 2000
|
||||
max_tokens: int = 131072
|
||||
model: Optional[str] = None
|
||||
provider: str = "opencode-go"
|
||||
base_url: Optional[str] = None
|
||||
|
||||
@@ -25,12 +25,14 @@
|
||||
<el-button size="default" :type="activeTab === 'cases' ? 'primary' : ''" @click="switchTab('cases')">案例管理</el-button>
|
||||
<el-button size="default" :type="activeTab === 'tasklogs' ? 'primary' : ''" @click="switchTab('tasklogs')">任务日志</el-button>
|
||||
<el-button size="default" :type="activeTab === 'llmconfigs' ? 'primary' : ''" @click="switchTab('llmconfigs')">LLM配置</el-button>
|
||||
<el-button size="default" :type="activeTab === 'platformconfigs' ? 'primary' : ''" @click="switchTab('platformconfigs')">平台配置</el-button>
|
||||
<el-button size="default" :type="activeTab === 'systemconfigs' ? 'primary' : ''" @click="switchTab('systemconfigs')">系统配置</el-button>
|
||||
<el-button size="default" :type="activeTab === 'users' ? 'primary' : ''" @click="switchTab('users')">用户管理</el-button>
|
||||
<el-button size="default" :type="activeTab === 'categories' ? 'primary' : ''" @click="switchTab('categories')">采集类别</el-button>
|
||||
<el-button size="default" :type="activeTab === 'sources' ? 'primary' : ''" @click="switchTab('sources')">信息源</el-button>
|
||||
<el-button size="default" :type="activeTab === 'orgs' ? 'primary' : ''" @click="switchTab('orgs')">组织管理</el-button>
|
||||
<el-button size="default" :type="activeTab === 'logs' ? 'primary' : ''" @click="switchTab('logs')">运行日志</el-button>
|
||||
<el-button size="default" :type="activeTab === 'assistant' ? 'primary' : ''" @click="switchTab('assistant')">AI 助手</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,10 +55,10 @@
|
||||
</div>
|
||||
<el-table :data="paginatedCases" border stripe class="data-table" style="width:100%">
|
||||
<el-table-column prop="id" label="ID" width="70"></el-table-column>
|
||||
<el-table-column prop="title" label="标题" min-width="120" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="field" label="领域" width="100"></el-table-column>
|
||||
<el-table-column prop="title" label="标题" min-width="80" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="field" label="领域" width="140"></el-table-column>
|
||||
<el-table-column prop="summary" label="概述" min-width="200" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="source" label="来源" width="100"></el-table-column>
|
||||
<el-table-column prop="source" label="来源" width="140"></el-table-column>
|
||||
<el-table-column label="操作" width="140" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="showCaseDialog(scope.row)">编辑</el-button>
|
||||
@@ -129,18 +131,25 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-table :data="llmConfigs" border stripe class="data-table" style="width:100%">
|
||||
<el-table-column prop="id" label="ID" width="70"></el-table-column>
|
||||
<el-table-column prop="name" label="名称" min-width="120"></el-table-column>
|
||||
<el-table-column prop="model" label="模型" min-width="180"></el-table-column>
|
||||
<el-table-column prop="temperature" label="温度" width="80"></el-table-column>
|
||||
<el-table-column prop="max_tokens" label="最大Token" width="110"></el-table-column>
|
||||
<el-table-column prop="is_active" label="激活" width="70">
|
||||
<el-table-column prop="id" label="ID" width="60"></el-table-column>
|
||||
<el-table-column prop="name" label="名称" min-width="100"></el-table-column>
|
||||
<el-table-column prop="provider" label="供应商" width="110"></el-table-column>
|
||||
<el-table-column prop="model" label="模型" min-width="160"></el-table-column>
|
||||
<el-table-column prop="base_url" label="接口地址" min-width="200">
|
||||
<template #default="scope">{{ scope.row.base_url ? scope.row.base_url.replace(/^https?:\/\//, '') : '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="temperature" label="温度" width="70"></el-table-column>
|
||||
<el-table-column prop="max_tokens" label="最大Token" width="100"></el-table-column>
|
||||
<el-table-column prop="is_active" label="激活" width="60">
|
||||
<template #default="scope">
|
||||
<el-icon v-if="scope.row.is_active" style="color:#67C23A;"><IconCheck /></el-icon>
|
||||
<el-icon v-else style="color:#F56C6C;"><IconClose /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="140" fixed="right">
|
||||
<el-table-column label="系统提示词" min-width="150">
|
||||
<template #default="scope">{{ (scope.row.system_prompt || '').slice(0, 30) }}{{ (scope.row.system_prompt || '').length > 30 ? '...' : '' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="130" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="showLLMConfigDialog(scope.row)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="deleteLLMConfig(scope.row.id)">删除</el-button>
|
||||
@@ -151,8 +160,9 @@
|
||||
<div class="card-list-mobile">
|
||||
<div v-for="item in llmConfigs" :key="item.id" class="card-item">
|
||||
<div class="card-row"><span class="card-label">名称</span><span class="card-value">{{ item.name }}</span></div>
|
||||
<div class="card-row"><span class="card-label">供应商</span><span class="card-value">{{ item.provider }}</span></div>
|
||||
<div class="card-row"><span class="card-label">模型</span><span class="card-value">{{ item.model }}</span></div>
|
||||
<div class="card-row"><span class="card-label">温度</span><span class="card-value">{{ item.temperature }}</span></div>
|
||||
<div class="card-row"><span class="card-label">温度/最大Token</span><span class="card-value">{{ item.temperature }} / {{ item.max_tokens }}</span></div>
|
||||
<div class="card-row"><span class="card-label">激活</span><span class="card-value">{{ item.is_active ? '是' : '否' }}</span></div>
|
||||
<div class="card-actions">
|
||||
<el-button size="small" @click="showLLMConfigDialog(item)">编辑</el-button>
|
||||
@@ -162,6 +172,45 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'platformconfigs'">
|
||||
<div class="toolbar">
|
||||
<el-button type="primary" size="small" @click="showPlatformConfigDialog()">新增配置</el-button>
|
||||
</div>
|
||||
<div v-if="platformConfigsLoading" class="card-loading">加载中...</div>
|
||||
<template v-else-if="platformConfigs.length === 0">
|
||||
<div class="empty-state">
|
||||
<el-icon style="font-size:48px;color:#c0c4cc;"><IconDocument /></el-icon>
|
||||
<div class="empty-text">暂无平台配置</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-table :data="platformConfigs" border stripe class="data-table" style="width:100%">
|
||||
<el-table-column prop="platform" label="标识" width="80"></el-table-column>
|
||||
<el-table-column prop="name" label="名称" width="80"></el-table-column>
|
||||
<el-table-column prop="website_url" label="平台网址" min-width="160">
|
||||
<template #default="scope"><a :href="scope.row.website_url" target="_blank" style="color:#409eff;">{{ scope.row.website_url }}</a></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字数范围" width="120">
|
||||
<template #default="scope">{{ scope.row.min_words }} - {{ scope.row.max_words }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="配图" width="100">
|
||||
<template #default="scope">{{ scope.row.requires_image ? `${scope.row.image_count_min}-${scope.row.image_count_max}张` : '不需要' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="api_endpoint" label="API地址" min-width="160"></el-table-column>
|
||||
<el-table-column prop="default_format" label="默认格式" min-width="160">
|
||||
<template #default="scope">{{ (scope.row.default_format || '').slice(0, 30) }}{{ (scope.row.default_format || '').length > 30 ? '...' : '' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="is_active" label="激活" width="60">
|
||||
<template #default="scope"><el-icon v-if="scope.row.is_active" style="color:#67C23A;"><IconCheck /></el-icon><el-icon v-else style="color:#F56C6C;"><IconClose /></el-icon></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="showPlatformConfigDialog(scope.row)">编辑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="activeTab === 'systemconfigs'">
|
||||
<div class="toolbar">
|
||||
<el-button type="primary" size="small" @click="showSystemConfigDialog()">新增配置</el-button>
|
||||
@@ -396,6 +445,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'assistant'">
|
||||
<div class="toolbar">
|
||||
<el-button type="primary" size="small" @click="saveAssistantPrompt" :loading="assistantSaving">保存配置</el-button>
|
||||
<span style="font-size:13px;color:#909399;margin-left:8px;">AI 助手在各页面右下角显示悬浮按钮,点击可打开对话窗口</span>
|
||||
</div>
|
||||
<el-form label-width="120px" style="max-width:700px;margin-top:16px;">
|
||||
<el-form-item label="系统提示词">
|
||||
<el-input type="textarea" v-model="assistantPrompt" :rows="12" placeholder="设置 AI 助手的角色和行为说明,留空则使用默认提示词"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用助手" v-if="false">
|
||||
<el-switch v-model="assistantEnabled"></el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'sources'">
|
||||
<div class="toolbar">
|
||||
<el-button type="primary" size="small" @click="showSourceDialog()">新增信息源</el-button>
|
||||
@@ -500,7 +564,7 @@
|
||||
<el-col :span="12"><el-form-item label="温度"><el-input-number v-model="llmConfigForm.temperature" :min="0" :max="2" :step="0.1" style="width:100%"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="最大Token"><el-input-number v-model="llmConfigForm.max_tokens" :min="1" :max="10000" style="width:100%"/></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="最大Token"><el-input-number v-model="llmConfigForm.max_tokens" :min="1" :max="999999" style="width:100%"/></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="激活"><el-switch v-model="llmConfigForm.is_active"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
@@ -516,6 +580,39 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="platformConfigDialogVisible" :title="platformConfigDialogTitle" width="750px" :close-on-click-modal="false">
|
||||
<el-form :model="platformConfigForm" label-width="110px">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8"><el-form-item label="标识"><el-input v-model="platformConfigForm.platform" :disabled="!!editingPlatformConfigPlatform" placeholder="zhihu"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="名称"><el-input v-model="platformConfigForm.name" placeholder="知乎"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="图标"><el-input v-model="platformConfigForm.icon" placeholder="📕"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="平台网址"><el-input v-model="platformConfigForm.website_url" placeholder="https://www.zhihu.com"/></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="API地址"><el-input v-model="platformConfigForm.api_endpoint" placeholder="https://api.zhihu.com"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="最少字数"><el-input-number v-model="platformConfigForm.min_words" :min="0" :max="50000" style="width:100%"/></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="最多字数"><el-input-number v-model="platformConfigForm.max_words" :min="0" :max="50000" style="width:100%"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="需要配图"><el-switch v-model="platformConfigForm.requires_image"/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="最少"><el-input-number v-model="platformConfigForm.image_count_min" :min="0" :max="20" style="width:100%"/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="最多"><el-input-number v-model="platformConfigForm.image_count_max" :min="0" :max="20" style="width:100%"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24"><el-form-item label="默认格式"><el-input type="textarea" v-model="platformConfigForm.default_format" :rows="2" placeholder="图文笔记,300-800字,emoji+标签"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24"><el-form-item label="活跃"><el-switch v-model="platformConfigForm.is_active"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="platformConfigDialogVisible=false">取消</el-button>
|
||||
<el-button type="primary" @click="savePlatformConfig">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="systemConfigDialogVisible" :title="systemConfigDialogTitle" width="600px" :close-on-click-modal="false">
|
||||
<el-form :model="systemConfigForm" label-width="80px">
|
||||
<el-row :gutter="16">
|
||||
@@ -666,7 +763,7 @@
|
||||
const llmConfigsLoading = ref(false);
|
||||
const llmConfigDialogVisible = ref(false);
|
||||
const llmConfigDialogTitle = ref('新增配置');
|
||||
const llmConfigForm = reactive({ id: null, name: '', system_prompt: '', user_prompt_template: '', temperature: 0.7, max_tokens: 2000, model: '', provider: 'opencode-go', base_url: '', api_key: '', is_active: true });
|
||||
const llmConfigForm = reactive({ id: null, name: '', system_prompt: '', user_prompt_template: '', temperature: 0.7, max_tokens: 131072, model: '', provider: 'opencode-go', base_url: '', api_key: '', is_active: true });
|
||||
const editingLLMConfigId = ref(null);
|
||||
|
||||
const loadLLMConfigs = async () => {
|
||||
@@ -679,14 +776,14 @@
|
||||
llmConfigDialogTitle.value = '编辑配置'; editingLLMConfigId.value = row.id;
|
||||
llmConfigForm.id = row.id; llmConfigForm.name = row.name; llmConfigForm.provider = row.provider || 'opencode-go';
|
||||
llmConfigForm.model = row.model || ''; llmConfigForm.base_url = row.base_url || ''; llmConfigForm.api_key = '';
|
||||
llmConfigForm.temperature = row.temperature ?? 0.7; llmConfigForm.max_tokens = row.max_tokens ?? 2000;
|
||||
llmConfigForm.temperature = row.temperature ?? 0.7; llmConfigForm.max_tokens = row.max_tokens ?? 131072;
|
||||
llmConfigForm.system_prompt = row.system_prompt || ''; llmConfigForm.user_prompt_template = row.user_prompt_template || '';
|
||||
llmConfigForm.is_active = row.is_active ?? true;
|
||||
} else {
|
||||
llmConfigDialogTitle.value = '新增配置'; editingLLMConfigId.value = null;
|
||||
llmConfigForm.id = null; llmConfigForm.name = ''; llmConfigForm.provider = 'opencode-go'; llmConfigForm.model = 'deepseek-v4-pro';
|
||||
llmConfigForm.base_url = 'https://opencode.ai/zen/go/v1'; llmConfigForm.api_key = ''; llmConfigForm.temperature = 0.7;
|
||||
llmConfigForm.max_tokens = 2000; llmConfigForm.system_prompt = ''; llmConfigForm.user_prompt_template = ''; llmConfigForm.is_active = true;
|
||||
llmConfigForm.max_tokens = 131072; llmConfigForm.system_prompt = ''; llmConfigForm.user_prompt_template = ''; llmConfigForm.is_active = true;
|
||||
}
|
||||
llmConfigDialogVisible.value = true;
|
||||
};
|
||||
@@ -702,6 +799,37 @@
|
||||
catch (e) { if (e !== 'cancel') ElMessage.error('删除失败: ' + e.message); }
|
||||
};
|
||||
|
||||
const platformConfigs = ref([]);
|
||||
const platformConfigsLoading = ref(false);
|
||||
const platformConfigDialogVisible = ref(false);
|
||||
const platformConfigDialogTitle = ref('新增配置');
|
||||
const platformConfigForm = reactive({ platform: '', name: '', icon: '', website_url: '', api_endpoint: '', min_words: 300, max_words: 3000, requires_image: false, image_count_min: 0, image_count_max: 0, default_format: '', is_active: true });
|
||||
const editingPlatformConfigPlatform = ref(null);
|
||||
const loadPlatformConfigs = async () => {
|
||||
platformConfigsLoading.value = true;
|
||||
try { platformConfigs.value = await api.get('/api/platform-config'); } catch (e) { ElMessage.error('加载平台配置失败: ' + e.message); }
|
||||
finally { platformConfigsLoading.value = false; }
|
||||
};
|
||||
const showPlatformConfigDialog = (row = null) => {
|
||||
if (row) {
|
||||
platformConfigDialogTitle.value = '编辑配置'; editingPlatformConfigPlatform.value = row.platform;
|
||||
Object.assign(platformConfigForm, { ...row });
|
||||
} else {
|
||||
platformConfigDialogTitle.value = '新增配置'; editingPlatformConfigPlatform.value = null;
|
||||
platformConfigForm.platform = ''; platformConfigForm.name = ''; platformConfigForm.icon = ''; platformConfigForm.website_url = ''; platformConfigForm.api_endpoint = '';
|
||||
platformConfigForm.min_words = 300; platformConfigForm.max_words = 3000; platformConfigForm.requires_image = false;
|
||||
platformConfigForm.image_count_min = 0; platformConfigForm.image_count_max = 0; platformConfigForm.default_format = ''; platformConfigForm.is_active = true;
|
||||
}
|
||||
platformConfigDialogVisible.value = true;
|
||||
};
|
||||
const savePlatformConfig = async () => {
|
||||
try {
|
||||
if (editingPlatformConfigPlatform.value) { await api.put(`/api/platform-config/${platformConfigForm.platform}`, platformConfigForm); ElMessage.success('更新成功'); }
|
||||
else { await api.post('/api/platform-config', platformConfigForm); ElMessage.success('创建成功'); }
|
||||
platformConfigDialogVisible.value = false; await loadPlatformConfigs();
|
||||
} catch (e) { ElMessage.error('保存失败: ' + e.message); }
|
||||
};
|
||||
|
||||
const systemConfigs = ref([]);
|
||||
const systemConfigsLoading = ref(false);
|
||||
const systemConfigDialogVisible = ref(false);
|
||||
@@ -841,6 +969,25 @@
|
||||
catch (e) { if (e !== 'cancel') ElMessage.error('删除失败: ' + e.message); }
|
||||
};
|
||||
|
||||
const assistantPrompt = ref('');
|
||||
const assistantEnabled = ref(true);
|
||||
const assistantSaving = ref(false);
|
||||
const loadAssistantConfig = async () => {
|
||||
try {
|
||||
const configs = await api.get('/api/admin/systemconfigs');
|
||||
const cfg = configs.find(c => c.key === 'assistant_system_prompt');
|
||||
assistantPrompt.value = cfg ? (typeof cfg.value === 'string' ? cfg.value : '') : '';
|
||||
} catch (e) { console.error('加载AI助手配置失败', e); }
|
||||
};
|
||||
const saveAssistantPrompt = async () => {
|
||||
assistantSaving.value = true;
|
||||
try {
|
||||
await api.post('/api/admin/systemconfigs', { key: 'assistant_system_prompt', value: assistantPrompt.value, description: 'AI 助手系统提示词' });
|
||||
ElementPlus.ElMessage.success('保存成功');
|
||||
} catch (e) { ElementPlus.ElMessage.error('保存失败: ' + e.message); }
|
||||
finally { assistantSaving.value = false; }
|
||||
};
|
||||
|
||||
const loadCategories = async () => {
|
||||
categoriesLoading.value = true;
|
||||
try { categories.value = await api.get('/api/admin/collector/categories'); } catch (e) { ElMessage.error('加载类别失败: ' + e.message); }
|
||||
@@ -896,10 +1043,10 @@
|
||||
|
||||
const tabLoaders = {
|
||||
cases: loadCases, tasklogs: loadTaskLogs,
|
||||
llmconfigs: loadLLMConfigs, systemconfigs: loadSystemConfigs,
|
||||
llmconfigs: loadLLMConfigs, platformconfigs: loadPlatformConfigs, systemconfigs: loadSystemConfigs,
|
||||
users: fetchUsers,
|
||||
categories: loadCategories, sources: loadSources,
|
||||
orgs: loadOrgs,
|
||||
orgs: loadOrgs, assistant: loadAssistantConfig,
|
||||
};
|
||||
const loadedTabs = new Set(['cases']);
|
||||
|
||||
@@ -924,6 +1071,7 @@
|
||||
casePage, casePageSize, paginatedCases,
|
||||
taskLogs, taskLogsLoading, loadTaskLogs,
|
||||
llmConfigs, llmConfigsLoading, llmConfigDialogVisible, llmConfigForm, llmConfigDialogTitle, showLLMConfigDialog, saveLLMConfig, deleteLLMConfig,
|
||||
platformConfigs, platformConfigsLoading, platformConfigDialogVisible, platformConfigForm, platformConfigDialogTitle, showPlatformConfigDialog, savePlatformConfig, editingPlatformConfigPlatform,
|
||||
systemConfigs, systemConfigsLoading, systemConfigDialogVisible, systemConfigForm, systemConfigDialogTitle, showSystemConfigDialog, saveSystemConfig, deleteSystemConfig,
|
||||
categories, categoriesLoading, categoryDialogVisible, categoryForm, categoryDialogTitle, showCategoryDialog, saveCategory, deleteCategory,
|
||||
categoryPage, categoryPageSize, paginatedCategories,
|
||||
@@ -934,7 +1082,8 @@
|
||||
logout, currentUser, isAdmin, redirectToPage,
|
||||
users, usersLoading, userDialogVisible, userSubmitting, userForm, userPage, userPageSize, paginatedUsers,
|
||||
fetchUsers, addUser, submitUser, deleteUser,
|
||||
logType, logDate, logContent, logsLoading, fetchLogs
|
||||
logType, logDate, logContent, logsLoading, fetchLogs,
|
||||
assistantPrompt, assistantEnabled, assistantSaving, saveAssistantPrompt,
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -944,5 +1093,6 @@
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
(function () {
|
||||
if (document.getElementById('ai-assistant-styles')) return;
|
||||
|
||||
var style = document.createElement('style');
|
||||
style.id = 'ai-assistant-styles';
|
||||
style.textContent = '\
|
||||
.ai-assistant-btn {\
|
||||
position: fixed; bottom: 24px; right: 24px;\
|
||||
z-index: 99999;\
|
||||
width: 52px; height: 52px;\
|
||||
border-radius: 50%;\
|
||||
background: linear-gradient(135deg, #2563eb, #1d4ed8);\
|
||||
color: #fff;\
|
||||
border: none;\
|
||||
cursor: pointer;\
|
||||
box-shadow: 0 4px 16px rgba(37,99,235,0.35);\
|
||||
display: flex; align-items: center; justify-content: center;\
|
||||
font-size: 22px;\
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\
|
||||
}\
|
||||
.ai-assistant-btn:hover { transform: scale(1.1); box-shadow: 0 6px 24px rgba(37,99,235,0.45); }\
|
||||
.ai-assistant-btn.open { transform: rotate(45deg); background: #f56c6c; box-shadow: 0 4px 16px rgba(245,108,108,0.35); }\
|
||||
.ai-assistant-panel {\
|
||||
position: fixed; bottom: 88px; right: 24px;\
|
||||
z-index: 99998;\
|
||||
width: 380px; height: 560px;\
|
||||
background: #fff;\
|
||||
border-radius: 16px;\
|
||||
box-shadow: 0 8px 40px rgba(0,0,0,0.15);\
|
||||
display: none;\
|
||||
flex-direction: column;\
|
||||
overflow: hidden;\
|
||||
animation: aiSlideUp 0.3s ease-out;\
|
||||
border: 1px solid #e5e7eb;\
|
||||
}\
|
||||
.ai-assistant-panel.open { display: flex; }\
|
||||
@keyframes aiSlideUp {\
|
||||
from { opacity: 0; transform: translateY(20px) scale(0.95); }\
|
||||
to { opacity: 1; transform: translateY(0) scale(1); }\
|
||||
}\
|
||||
.ai-assistant-header {\
|
||||
padding: 14px 16px;\
|
||||
background: linear-gradient(135deg, #2563eb, #1d4ed8);\
|
||||
color: #fff;\
|
||||
font-weight: 600;\
|
||||
font-size: 15px;\
|
||||
display: flex; align-items: center; gap: 8px;\
|
||||
flex-shrink: 0;\
|
||||
}\
|
||||
.ai-assistant-header .ai-badge {\
|
||||
background: rgba(255,255,255,0.2);\
|
||||
padding: 2px 8px; border-radius: 10px;\
|
||||
font-size: 10px; font-weight: 400;\
|
||||
}\
|
||||
.ai-assistant-messages {\
|
||||
flex: 1; overflow-y: auto;\
|
||||
padding: 12px 16px;\
|
||||
background: #f8f9fb;\
|
||||
display: flex; flex-direction: column; gap: 10px;\
|
||||
}\
|
||||
.ai-assistant-msg {\
|
||||
max-width: 85%;\
|
||||
padding: 10px 14px;\
|
||||
border-radius: 12px;\
|
||||
font-size: 13px;\
|
||||
line-height: 1.6;\
|
||||
word-break: break-word;\
|
||||
white-space: pre-wrap;\
|
||||
}\
|
||||
.ai-assistant-msg.ai {\
|
||||
background: #fff;\
|
||||
border: 1px solid #e5e7eb;\
|
||||
color: #303133;\
|
||||
align-self: flex-start;\
|
||||
border-bottom-left-radius: 4px;\
|
||||
}\
|
||||
.ai-assistant-msg.user {\
|
||||
background: #2563eb;\
|
||||
color: #fff;\
|
||||
align-self: flex-end;\
|
||||
border-bottom-right-radius: 4px;\
|
||||
}\
|
||||
.ai-assistant-msg .msg-time {\
|
||||
font-size: 10px; opacity: 0.6;\
|
||||
margin-top: 4px; display: block;\
|
||||
}\
|
||||
.ai-assistant-typing {\
|
||||
align-self: flex-start;\
|
||||
display: flex; gap: 4px;\
|
||||
padding: 12px 16px;\
|
||||
background: #fff;\
|
||||
border: 1px solid #e5e7eb;\
|
||||
border-radius: 12px;\
|
||||
border-bottom-left-radius: 4px;\
|
||||
}\
|
||||
.ai-assistant-typing span {\
|
||||
width: 6px; height: 6px;\
|
||||
background: #909399;\
|
||||
border-radius: 50%;\
|
||||
animation: aiBounce 1.4s ease-in-out infinite;\
|
||||
}\
|
||||
.ai-assistant-typing span:nth-child(2) { animation-delay: 0.2s; }\
|
||||
.ai-assistant-typing span:nth-child(3) { animation-delay: 0.4s; }\
|
||||
@keyframes aiBounce {\
|
||||
0%, 60%, 100% { transform: translateY(0); }\
|
||||
30% { transform: translateY(-6px); }\
|
||||
}\
|
||||
.ai-assistant-input {\
|
||||
display: flex; align-items: center;\
|
||||
padding: 10px 12px;\
|
||||
border-top: 1px solid #e5e7eb;\
|
||||
background: #fff;\
|
||||
flex-shrink: 0;\
|
||||
gap: 8px;\
|
||||
}\
|
||||
.ai-assistant-input textarea {\
|
||||
flex: 1;\
|
||||
border: 1px solid #d1d5db;\
|
||||
border-radius: 8px;\
|
||||
padding: 8px 12px;\
|
||||
font-size: 13px;\
|
||||
outline: none;\
|
||||
resize: none;\
|
||||
height: 36px;\
|
||||
line-height: 20px;\
|
||||
font-family: inherit;\
|
||||
transition: border-color 0.2s;\
|
||||
}\
|
||||
.ai-assistant-input textarea:focus { border-color: #2563eb; }\
|
||||
.ai-assistant-send {\
|
||||
width: 36px; height: 36px;\
|
||||
border-radius: 8px;\
|
||||
background: #2563eb;\
|
||||
color: #fff;\
|
||||
border: none;\
|
||||
cursor: pointer;\
|
||||
font-size: 16px;\
|
||||
display: flex; align-items: center; justify-content: center;\
|
||||
transition: all 0.2s;\
|
||||
flex-shrink: 0;\
|
||||
}\
|
||||
.ai-assistant-send:hover { background: #1d4ed8; }\
|
||||
.ai-assistant-send:disabled { background: #c0c4cc; cursor: not-allowed; }\
|
||||
.ai-assistant-greeting {\
|
||||
text-align: center;\
|
||||
padding: 20px 16px;\
|
||||
color: #909399;\
|
||||
font-size: 13px;\
|
||||
}\
|
||||
.ai-assistant-greeting .greeting-icon {\
|
||||
font-size: 36px; margin-bottom: 8px;\
|
||||
}\
|
||||
.ai-assistant-greeting h4 {\
|
||||
color: #303133; font-size: 15px;\
|
||||
margin: 0 0 6px;\
|
||||
}\
|
||||
@media (max-width: 480px) {\
|
||||
.ai-assistant-panel {\
|
||||
right: 12px; left: 12px;\
|
||||
width: auto;\
|
||||
height: 480px;\
|
||||
bottom: 80px;\
|
||||
}\
|
||||
.ai-assistant-btn { right: 16px; bottom: 16px; }\
|
||||
}\
|
||||
';
|
||||
document.head.appendChild(style);
|
||||
|
||||
var token = localStorage.getItem('authToken');
|
||||
if (!token) return;
|
||||
|
||||
var pageMap = {
|
||||
'/': 'dashboard', '/index.html': 'dashboard',
|
||||
'topics.html': 'topics', 'metrics.html': 'metrics',
|
||||
'calendar.html': 'calendar', 'assets.html': 'assets',
|
||||
'tasks.html': 'tasks', 'platforms.html': 'platforms',
|
||||
'admin.html': 'admin'
|
||||
};
|
||||
var path = window.location.pathname;
|
||||
var currentPage = pageMap[path] || pageMap['/'];
|
||||
|
||||
var greettings = {
|
||||
'dashboard': '👋 欢迎回来!我可以帮你了解仪表盘上的统计数据、模块状态的含义,或指导你如何快速定位待处理选题。',
|
||||
'topics': '📝 这里是选题管理。我可以帮你了解如何创建选题、设置评分、编辑内容,或如何使用预览功能查看各平台文章效果。',
|
||||
'metrics': '📊 数据分析页展示内容表现。我可以帮你解读图表数据、分析各平台效果差异,或建议如何提升内容互动率。',
|
||||
'calendar': '📅 内容日历帮你规划发布节奏。我可以教你如何创建计划、调整日期,或优化内容排期策略。',
|
||||
'assets': '🖼️ 素材库管理图片和文件。我可以指导你如何上传素材、添加标签分类,或关联到相关选题。',
|
||||
'tasks': '⚡ 任务页面跟踪所有创作任务。我可以解释各任务的含义、查看执行进度,或排查任务失败原因。',
|
||||
'platforms': '🔗 平台配置管理各发布渠道。我可以帮你了解如何配置平台参数、设置发布格式。',
|
||||
'admin': '⚙️ 系统管理页面。我可以帮你管理用户、配置 LLM、查看运行日志,或设置采集类别和信息源。',
|
||||
};
|
||||
|
||||
var HISTORY_KEY = 'ai_assistant_history_' + currentPage;
|
||||
var saved = [];
|
||||
try { saved = JSON.parse(localStorage.getItem(HISTORY_KEY)) || []; } catch(e) {}
|
||||
|
||||
var container = document.createElement('div');
|
||||
container.innerHTML = '\
|
||||
<button class="ai-assistant-btn" id="aiAssistantBtn" title="AI 助手">\
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\
|
||||
<path d="M12 2a4 4 0 0 1 4 4v2a4 4 0 0 1-8 0V6a4 4 0 0 1 4-4z"/>\
|
||||
<path d="M16 14H8a4 4 0 0 0-4 4v2h16v-2a4 4 0 0 0-4-4z"/>\
|
||||
<circle cx="9" cy="10" r="1" fill="currentColor"/>\
|
||||
<circle cx="15" cy="10" r="1" fill="currentColor"/>\
|
||||
<path d="M12 14v2"/>\
|
||||
</svg>\
|
||||
</button>\
|
||||
<div class="ai-assistant-panel" id="aiAssistantPanel">\
|
||||
<div class="ai-assistant-header">\
|
||||
<span>🤖 AI 助手</span>\
|
||||
<span class="ai-badge">' + currentPage + '</span>\
|
||||
</div>\
|
||||
<div class="ai-assistant-messages" id="aiMessages">\
|
||||
</div>\
|
||||
<div class="ai-assistant-input">\
|
||||
<textarea id="aiInput" rows="1" placeholder="输入你的问题..." maxlength="500"></textarea>\
|
||||
<button class="ai-assistant-send" id="aiSendBtn">\
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\
|
||||
<line x1="22" y1="2" x2="11" y2="13"/>\
|
||||
<polygon points="22 2 15 22 11 13 2 9 22 2"/>\
|
||||
</svg>\
|
||||
</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
';
|
||||
document.body.appendChild(container);
|
||||
|
||||
var btn = document.getElementById('aiAssistantBtn');
|
||||
var panel = document.getElementById('aiAssistantPanel');
|
||||
var messagesEl = document.getElementById('aiMessages');
|
||||
var input = document.getElementById('aiInput');
|
||||
var sendBtn = document.getElementById('aiSendBtn');
|
||||
|
||||
function addMessage(role, content) {
|
||||
var div = document.createElement('div');
|
||||
div.className = 'ai-assistant-msg ' + role;
|
||||
div.textContent = content;
|
||||
messagesEl.appendChild(div);
|
||||
messagesEl.scrollTop = messagesEl.scrollHeight;
|
||||
}
|
||||
|
||||
function showGreeting() {
|
||||
messagesEl.innerHTML = '\
|
||||
<div class="ai-assistant-greeting">\
|
||||
<div class="greeting-icon">🤖</div>\
|
||||
<h4>宇之然 AI 助手</h4>\
|
||||
<p>' + (greettings[currentPage] || '👋 你好!有什么可以帮助你的?') + '</p>\
|
||||
</div>';
|
||||
}
|
||||
|
||||
function showTyping() {
|
||||
var div = document.createElement('div');
|
||||
div.className = 'ai-assistant-typing';
|
||||
div.id = 'aiTyping';
|
||||
div.innerHTML = '<span></span><span></span><span></span>';
|
||||
messagesEl.appendChild(div);
|
||||
messagesEl.scrollTop = messagesEl.scrollHeight;
|
||||
}
|
||||
|
||||
function removeTyping() {
|
||||
var t = document.getElementById('aiTyping');
|
||||
if (t) t.remove();
|
||||
}
|
||||
|
||||
function saveHistory(history) {
|
||||
try {
|
||||
localStorage.setItem(HISTORY_KEY, JSON.stringify(history.slice(-50)));
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
async function sendMessage(text) {
|
||||
if (!text.trim()) return;
|
||||
input.value = '';
|
||||
input.style.height = '36px';
|
||||
addMessage('user', text);
|
||||
if (messagesEl.querySelector('.ai-assistant-greeting')) {
|
||||
messagesEl.querySelector('.ai-assistant-greeting').remove();
|
||||
}
|
||||
sendBtn.disabled = true;
|
||||
|
||||
var history = [];
|
||||
var msgs = messagesEl.querySelectorAll('.ai-assistant-msg');
|
||||
msgs.forEach(function(m) {
|
||||
history.push({ role: m.classList.contains('user') ? 'user' : 'assistant', content: m.textContent });
|
||||
});
|
||||
|
||||
showTyping();
|
||||
try {
|
||||
var resp = await fetch('/api/assistant/chat', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token },
|
||||
body: JSON.stringify({ message: text, page: currentPage, history: history })
|
||||
});
|
||||
removeTyping();
|
||||
if (resp.ok) {
|
||||
var data = await resp.json();
|
||||
addMessage('assistant', data.reply || '已收到');
|
||||
saveHistory(history.concat([
|
||||
{ role: 'user', content: text },
|
||||
{ role: 'assistant', content: data.reply || '已收到' }
|
||||
]));
|
||||
} else {
|
||||
addMessage('assistant', '抱歉,请求失败,请稍后重试。');
|
||||
}
|
||||
} catch(e) {
|
||||
removeTyping();
|
||||
addMessage('assistant', '网络异常,请检查连接后重试。');
|
||||
}
|
||||
sendBtn.disabled = false;
|
||||
input.focus();
|
||||
}
|
||||
|
||||
// Open/close
|
||||
var isOpen = false;
|
||||
btn.addEventListener('click', function() {
|
||||
isOpen = !isOpen;
|
||||
btn.classList.toggle('open', isOpen);
|
||||
panel.classList.toggle('open', isOpen);
|
||||
if (isOpen) {
|
||||
var msgs = messagesEl.querySelectorAll('.ai-assistant-msg');
|
||||
if (msgs.length === 0) {
|
||||
// Load saved or show greeting
|
||||
if (saved.length > 0) {
|
||||
saved.forEach(function(m) { addMessage(m.role, m.content); });
|
||||
} else {
|
||||
showGreeting();
|
||||
}
|
||||
}
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Send on click
|
||||
sendBtn.addEventListener('click', function() { sendMessage(input.value); });
|
||||
|
||||
// Send on Enter (Shift+Enter for newline)
|
||||
input.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
sendMessage(input.value);
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-resize textarea
|
||||
input.addEventListener('input', function() {
|
||||
this.style.height = '36px';
|
||||
this.style.height = Math.min(this.scrollHeight, 120) + 'px';
|
||||
});
|
||||
|
||||
// Close on Escape
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && isOpen) {
|
||||
isOpen = false;
|
||||
btn.classList.remove('open');
|
||||
panel.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
window.aiAssistantOpen = function() { btn.click(); };
|
||||
window.aiAssistantClose = function() { if (isOpen) btn.click(); };
|
||||
})();
|
||||
@@ -257,5 +257,6 @@ if (window.installIcons) { window.installIcons(app); }
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -246,5 +246,6 @@ if (window.installIcons) { window.installIcons(app); }
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -96,9 +96,9 @@
|
||||
<div class="calendar-header">
|
||||
<h2 class="calendar-title"><el-icon style="vertical-align:-2px;"><IconCalendar /></el-icon> 内容日历</h2>
|
||||
<div class="calendar-nav">
|
||||
<el-button @click="prevMonth" size="large"><el-icon><IconArrowLeft /></el-icon></el-button>
|
||||
<el-button @click="prevMonth" size="large"><el-icon><IconArrowLeft /></el-icon> 上月</el-button>
|
||||
<span style="font-size: 20px; font-weight: 600;">{{ currentYear }}年 {{ currentMonth }}月</span>
|
||||
<el-button @click="nextMonth" size="large"><el-icon><IconArrowRight /></el-icon></el-button>
|
||||
<el-button @click="nextMonth" size="large">下月 <el-icon><IconArrowRight /></el-icon></el-button>
|
||||
<el-button type="primary" @click="goToday">今天</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -490,5 +490,6 @@ function getDayMeta(year, month, day) {
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -102,8 +102,13 @@
|
||||
</div>
|
||||
<div class="module-content">
|
||||
<div><span>最后运行</span><span>{{ mod.last_run }}</span></div>
|
||||
<div><span>下次运行</span><span>{{ mod.next_run }}</span></div>
|
||||
<div><span>今日任务</span><span>{{ mod.task_count }} 个</span></div>
|
||||
<div v-if="mod.success_rate !== null"><span>成功率</span><span>{{ mod.success_rate }}%</span></div>
|
||||
<div><span>成功率</span><span>{{ mod.success_rate > 0 ? mod.success_rate + '%' : '暂无' }}</span></div>
|
||||
<div style="margin-top:10px; border-bottom:none;">
|
||||
<el-button v-if="mod.id === 'scheduled_optimize_sources'" size="small" type="primary" @click="triggerModule(mod.id)" :loading="runningModule === mod.id">立即运行</el-button>
|
||||
<el-button v-if="mod.id === 'scheduled_metrics_sync'" size="small" type="primary" @click="triggerModule(mod.id)" :loading="runningModule === mod.id">立即运行</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -158,7 +163,8 @@
|
||||
schedulerStatus: '',
|
||||
schedulerRunning: false,
|
||||
upcomingEntries: [],
|
||||
loadingPlan: false
|
||||
loadingPlan: false,
|
||||
runningModule: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -276,6 +282,24 @@
|
||||
const url = filter ? '/topics.html?filter=' + encodeURIComponent(filter) : '/topics.html';
|
||||
window.location.href = url;
|
||||
},
|
||||
async triggerModule(modId) {
|
||||
this.runningModule = modId;
|
||||
try {
|
||||
const token = localStorage.getItem('authToken');
|
||||
const endpoint = modId === 'scheduled_optimize_sources' ? '/api/system/optimize-sources/run' : '/api/system/metrics-sync/run';
|
||||
const resp = await fetch(endpoint, { method: 'POST', headers: { 'Authorization': 'Bearer ' + token } });
|
||||
if (resp.ok) {
|
||||
const data = await resp.json();
|
||||
this.$message.success(data.message || '执行成功');
|
||||
this.fetchModules();
|
||||
} else {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
this.$message.error(err.detail || '执行失败');
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error('执行失败: ' + e.message);
|
||||
} finally { this.runningModule = null; }
|
||||
},
|
||||
redirectToPage(page) {
|
||||
window.location.href = page.startsWith('/') ? page : '/' + page;
|
||||
}
|
||||
@@ -312,5 +336,6 @@
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -369,5 +369,6 @@ if (window.installIcons) { window.installIcons(app); }
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -246,5 +246,6 @@ if (window.installIcons) { window.installIcons(app); }
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -292,5 +292,6 @@ if (window.installIcons) { window.installIcons(app); }
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
<link rel="stylesheet" href="theme-modern.css">
|
||||
<style>
|
||||
.selected-count { color: var(--color-text-secondary); font-size: var(--font-size-body); margin-left: auto; }
|
||||
.preview-dialog-custom .el-dialog__body { overflow-y: auto; max-height: calc(90vh - 120px); padding: 16px 20px; }
|
||||
.preview-dialog-custom .preview-body { max-height: none !important; min-height: 300px; overflow: visible; }
|
||||
.preview-dialog-custom .preview-body img { max-width: 100%; }
|
||||
.topic-card-list { display: none; }
|
||||
@media (max-width: 768px) {
|
||||
.el-table { display: none; }
|
||||
@@ -50,7 +53,7 @@
|
||||
<el-button size="default" :type="filterStatus === 'ready' ? 'primary' : ''" @click="filterStatus = 'ready'; fetchTopics()">待发布 ({{ statusStats.ready }})</el-button>
|
||||
<el-button size="default" :type="filterStatus === 'published' ? 'primary' : ''" @click="filterStatus = 'published'; fetchTopics()">已发布 ({{ statusStats.published }})</el-button>
|
||||
</div>
|
||||
<el-table :data="paginatedTopics" stripe v-loading="loadingTable" @selection-change="selectedTopicIds = $event.map(item => item.id)">
|
||||
<el-table ref="topicTable" :data="paginatedTopics" stripe v-loading="loadingTable" @selection-change="selectedTopicIds = $event.map(item => item.id)">
|
||||
<el-table-column type="selection" width="55"></el-table-column>
|
||||
<el-table-column prop="id" label="ID" width="70" fixed></el-table-column>
|
||||
<el-table-column prop="title" label="标题" min-width="200"></el-table-column>
|
||||
@@ -160,7 +163,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div style="width:100%;">
|
||||
<div v-if="!editing" class="preview-body" style="min-height:300px; height:68vh; border:1px solid #ebeef5; border-radius:8px; background:#fff; padding:20px; overflow-y:auto; width:100%; line-height:1.8;" v-html="currentPreviewBody"></div>
|
||||
<div v-if="!editing" class="preview-body" style="border:1px solid #ebeef5; border-radius:8px; background:#fff; padding:20px; width:100%; line-height:1.8;" v-html="currentPreviewBody"></div>
|
||||
<div v-else ref="editor" contenteditable="true" style="min-height:300px; height:68vh; border:1px solid #409eff; border-radius:8px; background:#fff; padding:20px; overflow-y:auto; width:100%; line-height:1.8; outline:none; box-shadow:0 0 0 2px rgba(64,158,255,0.2);" @input="editContent = $event.target.innerHTML"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -237,11 +240,13 @@ const TopicsApp = {
|
||||
currentPreviewBody() {
|
||||
const html = this.platformContents[this.previewPlatform];
|
||||
if (!html) return '';
|
||||
if (html.length < 50) return '<div style="padding:40px;text-align:center;color:#909399;"><p style="font-size:36px;margin:0 0 12px;">📝</p><p>该平台内容暂未生成或内容为空</p><p style="font-size:13px;margin-top:8px;">可点击上方「批量创作」重新生成,或在编辑模式下手动添加内容</p></div>';
|
||||
try {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const body = doc.body;
|
||||
if (!body) return html;
|
||||
if (body.innerHTML.length < 30) return '<div style="padding:40px;text-align:center;color:#909399;"><p style="font-size:36px;margin:0 0 12px;">📝</p><p>内容为空,请编辑或重新生成</p></div>';
|
||||
body.querySelectorAll('script, nav, .header, .tags, footer, .interaction').forEach(el => el.remove());
|
||||
return body.innerHTML;
|
||||
} catch (e) { console.error('解析 HTML 失败:', e); return html; }
|
||||
@@ -340,8 +345,18 @@ const TopicsApp = {
|
||||
},
|
||||
platformName(platform) { return { zhihu: '知乎', wechat: '微信公众号', xiaohongshu: '小红书' }[platform] || platform; },
|
||||
copyContent(platform) {
|
||||
if (!this.previewTopic || !this.previewTopic.content) { this.$message.warning('暂无内容可复制'); return; }
|
||||
navigator.clipboard.writeText(`标题:${this.previewTopic.title}\n\n内容:\n${this.previewTopic.content}`)
|
||||
const html = this.platformContents[platform];
|
||||
if (!html) { this.$message.warning('暂无内容可复制'); return; }
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const titleEl = doc.querySelector('h1');
|
||||
const title = titleEl ? titleEl.textContent.trim() : (this.previewTopic?.title || '');
|
||||
const body = doc.body;
|
||||
if (body) {
|
||||
body.querySelectorAll('script, nav, .header, .tags, footer, .interaction').forEach(el => el.remove());
|
||||
}
|
||||
const text = body ? body.textContent.trim() : html.replace(/<[^>]+>/g, '').trim();
|
||||
navigator.clipboard.writeText(`标题:${title}\n\n内容:\n${text}`)
|
||||
.then(() => this.$message.success(`已复制内容,请前往${platform}粘贴发布`))
|
||||
.catch(() => this.$message.error('复制失败,请手动复制'));
|
||||
},
|
||||
@@ -433,13 +448,12 @@ const TopicsApp = {
|
||||
}
|
||||
},
|
||||
toggleSelectAll() {
|
||||
const visible = this.filteredTopics.map(t => t.id);
|
||||
const allChecked = visible.every(id => this.selectedTopicIds.includes(id));
|
||||
if (allChecked) {
|
||||
this.selectedTopicIds = this.selectedTopicIds.filter(id => !visible.includes(id));
|
||||
} else {
|
||||
const existing = new Set(this.selectedTopicIds);
|
||||
for (const id of visible) { if (!existing.has(id)) { this.selectedTopicIds.push(id); } }
|
||||
const table = this.$refs.topicTable;
|
||||
if (!table) return;
|
||||
const visible = this.filteredTopics;
|
||||
const allChecked = visible.every(t => this.selectedTopicIds.includes(t.id));
|
||||
for (const row of visible) {
|
||||
table.toggleRowSelection(row, !allChecked);
|
||||
}
|
||||
},
|
||||
formatDate(dateStr) {
|
||||
@@ -467,5 +481,6 @@ if (window.installIcons) { window.installIcons(app); }
|
||||
if (window.installUniNav) { window.installUniNav(app); }
|
||||
app.mount('#app');
|
||||
</script>
|
||||
<script src="ai-assistant.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AI 配图生成器 - 使用 sensenova API 生成文章配图
|
||||
支持 OpenAI 兼容格式的图片生成 API
|
||||
"""
|
||||
|
||||
import os, sys, json, datetime, logging, requests, base64
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path('/root/openclaw-workspace/projects/yu-zhi-ran')
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
sys.path.insert(0, str(PROJECT_ROOT / 'platform' / 'backend'))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(str(PROJECT_ROOT / 'platform' / 'backend' / '.env'))
|
||||
|
||||
LOGS_DIR = PROJECT_ROOT / "automation" / "logs"
|
||||
TODAY = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(LOGS_DIR / f"ai_image_{TODAY}.log"),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SENSENOVA_API_KEY = os.getenv("SENSENOVA_API_KEY", "sk-2Bbcf8pSTSl1x2BV5fKtDsUIGdfjKX7M")
|
||||
SENSENOVA_BASE_URL = os.getenv("SENSENOVA_BASE_URL", "https://token.sensenova.cn/v1")
|
||||
SENSENOVA_MODEL = os.getenv("SENSENOVA_IMAGE_MODEL", "sensenova-u1-fast")
|
||||
|
||||
# Platform image size mapping
|
||||
PLATFORM_SIZES = {
|
||||
"zhihu": "1760x2368",
|
||||
"wechat": "1760x2368",
|
||||
"xiaohongshu": "1664x2496",
|
||||
}
|
||||
|
||||
def generate_image(prompt: str, platform: str = "zhihu", size: str = None) -> str:
|
||||
if not size:
|
||||
size = PLATFORM_SIZES.get(platform, "2048x2048")
|
||||
headers = {
|
||||
"Authorization": f"Bearer {SENSENOVA_API_KEY}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
payload = {
|
||||
"model": SENSENOVA_MODEL,
|
||||
"prompt": prompt,
|
||||
"n": 1,
|
||||
"size": size,
|
||||
"response_format": "b64_json",
|
||||
}
|
||||
try:
|
||||
resp = requests.post(
|
||||
f"{SENSENOVA_BASE_URL}/images/generations",
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=120,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
if "data" in data and len(data["data"]) > 0:
|
||||
item = data["data"][0]
|
||||
if "b64_json" in item:
|
||||
return item["b64_json"]
|
||||
if "url" in item:
|
||||
img_resp = requests.get(item["url"], timeout=60)
|
||||
if img_resp.status_code == 200:
|
||||
return base64.b64encode(img_resp.content).decode("ascii")
|
||||
logger.error(f"API 返回格式异常: {json.dumps(data, ensure_ascii=False)[:500]}")
|
||||
else:
|
||||
logger.error(f"API 请求失败: {resp.status_code} {resp.text[:500]}")
|
||||
except requests.Timeout:
|
||||
logger.error("API 请求超时")
|
||||
except Exception as e:
|
||||
logger.error(f"生成图片失败: {e}")
|
||||
return None
|
||||
|
||||
def generate_article_images(topic_id: str, title: str, field: str = "", platforms: list = None) -> dict:
|
||||
if platforms is None:
|
||||
platforms = ["zhihu", "wechat", "xiaohongshu"]
|
||||
output_dir = PROJECT_ROOT / "automation" / "images" / "generated" / TODAY
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
results = {}
|
||||
for platform in platforms:
|
||||
platform_results = {}
|
||||
for img_type, prompt_template in [
|
||||
("cover", f"为文章《{title}》生成一张高质量的封面配图,领域:{field}。风格:简约现代,色彩柔和专业,适合{platform}平台。不要文字。"),
|
||||
("illustration", f"为文章《{title}》(领域:{field})生成一张内容插图,表现核心概念。风格:清新自然,适合{platform}平台。"),
|
||||
]:
|
||||
img_b64 = generate_image(prompt_template, platform)
|
||||
if img_b64:
|
||||
filename = f"{img_type}_{platform}_{topic_id}.png"
|
||||
filepath = output_dir / filename
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(base64.b64decode(img_b64))
|
||||
platform_results[img_type] = str(filepath)
|
||||
logger.info(f"[{platform}] {img_type} 生成成功: {filename}")
|
||||
else:
|
||||
logger.warning(f"[{platform}] {img_type} 生成失败,跳过")
|
||||
results[platform] = platform_results
|
||||
return results
|
||||
|
||||
def save_images_to_db(topic_id: str, platform: str, images: dict):
|
||||
try:
|
||||
from app.database import SessionLocal
|
||||
from app.models import Article
|
||||
db = SessionLocal()
|
||||
article_id = f"{platform}_{topic_id}"
|
||||
article = db.query(Article).filter(Article.id == article_id).first()
|
||||
if article:
|
||||
existing = article.images or {}
|
||||
existing.update(images)
|
||||
article.images = existing
|
||||
db.commit()
|
||||
logger.info(f"[{platform}] 图片路径已保存到 DB")
|
||||
db.close()
|
||||
except Exception as e:
|
||||
logger.error(f"保存图片路径到 DB 失败: {e}")
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="AI 配图生成器")
|
||||
parser.add_argument("--topic-id", required=True, help="选题ID")
|
||||
parser.add_argument("--title", help="文章标题")
|
||||
parser.add_argument("--field", default="", help="领域")
|
||||
args = parser.parse_args()
|
||||
from db_helper import get_topic_by_id
|
||||
topic = get_topic_by_id(args.topic_id)
|
||||
if not topic:
|
||||
print(json.dumps({"ok": False, "error": f"Topic {args.topic_id} not found"}))
|
||||
sys.exit(1)
|
||||
title = args.title or topic.get("title", "")
|
||||
field = args.field or topic.get("field", "")
|
||||
logger.info(f"为选题 {args.topic_id} 《{title}》生成配图...")
|
||||
results = generate_article_images(args.topic_id, title, field)
|
||||
for platform, imgs in results.items():
|
||||
if imgs:
|
||||
save_images_to_db(args.topic_id, platform, imgs)
|
||||
output = {"ok": True, "topic_id": args.topic_id, "images": results}
|
||||
print(json.dumps(output, ensure_ascii=False))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -431,7 +431,7 @@ class SustainabilityCollector:
|
||||
只输出JSON,不要其他文字。"""
|
||||
|
||||
try:
|
||||
resp = call_llm(prompt, temperature=0.7, max_tokens=800)
|
||||
resp = call_llm(prompt, temperature=0.7)
|
||||
resp = resp.strip()
|
||||
if resp.startswith("```"):
|
||||
resp = resp.split("\n", 1)[1].rsplit("\n", 1)[0]
|
||||
|
||||
@@ -163,8 +163,11 @@ def polish_with_llm(html: str, platform: str, remaining_issues: Optional[List[Di
|
||||
- 短句化,读起来更流畅"""
|
||||
polished = call_llm(polish_prompt, model=model, temperature=temperature, max_tokens=max_tokens, system_prompt=system_prompt)
|
||||
if '<h2' in polished or '<p>' in polished:
|
||||
tag = "针对性修复" if remaining_issues else "常规润色"
|
||||
return polished, f"LLM {tag}"
|
||||
if len(polished) > len(html) * 0.3 and len(polished) > 100:
|
||||
if not any(kw in polished[:100] for kw in ['保留', '建议', '可以', '应该', '推荐']):
|
||||
tag = "针对性修复" if remaining_issues else "常规润色"
|
||||
return polished, f"LLM {tag}"
|
||||
logger.warning(f"LLM 优化输出异常(过短或含建议性文字),保留原文 (len={len(polished)})")
|
||||
except Exception as e:
|
||||
logger.warning(f"LLM 优化失败: {e}")
|
||||
return html, None
|
||||
|
||||
@@ -102,8 +102,10 @@ def run_pipeline(topic_id: str = None) -> Dict:
|
||||
update_topic_status(tid, 'pending')
|
||||
return {"ok": False, "error": "writer step failed"}
|
||||
|
||||
# 4. 配图生成
|
||||
image_ok = run_step("image_generator.py", tid)
|
||||
# 4. 配图生成(AI版,失败时回退PIL版)
|
||||
image_ok = run_step("ai_image_generator.py", tid)
|
||||
if not image_ok:
|
||||
image_ok = run_step("image_generator.py", tid)
|
||||
|
||||
# 5. 合规优化(自动审核并标记为「待发布」)
|
||||
if not run_optimizer_step(tid):
|
||||
|
||||
@@ -102,7 +102,7 @@ class Outliner:
|
||||
|
||||
直接输出大纲,不要输出思考过程。"""
|
||||
try:
|
||||
outline = call_llm(prompt, temperature=0.6, max_tokens=2000, system_prompt="你是一个有经验的内容编辑,擅长为不同选题设计差异化的文章结构。")
|
||||
outline = call_llm(prompt, temperature=0.6, system_prompt="你是一个有经验的内容编辑,擅长为不同选题设计差异化的文章结构。")
|
||||
logger.info(f"LLM 大纲生成成功,长度:{len(outline)}")
|
||||
return f"# 文章大纲:{title}\n\n{outline}\n\n---\n*大纲生成时间:{TODAY}*"
|
||||
except Exception as e:
|
||||
|
||||
@@ -102,7 +102,7 @@ class Researcher:
|
||||
|
||||
风格:说人话,直击要点,像资深编辑在给作者做 briefing。避免「首先其次最后」「综上所述」。直接输出内容,不要输出思考过程。"""
|
||||
try:
|
||||
return call_llm(prompt, temperature=0.5, max_tokens=1200, system_prompt="你是一个行业研究员,擅长从案例中发现真洞察。")
|
||||
return call_llm(prompt, temperature=0.5, system_prompt="你是一个行业研究员,擅长从案例中发现真洞察。")
|
||||
except Exception as e:
|
||||
logger.warning(f"LLM 研究发现摘要生成失败: {e}")
|
||||
return ""
|
||||
|
||||
@@ -120,7 +120,7 @@ def generate_new_topics(gaps: List[Dict]) -> List[Dict]:
|
||||
|
||||
只输出 JSON 数组,不要其他文字。"""
|
||||
try:
|
||||
resp = call_llm(prompt, temperature=0.4, max_tokens=2000)
|
||||
resp = call_llm(prompt, temperature=0.4)
|
||||
resp = resp.strip()
|
||||
if resp.startswith("```"):
|
||||
resp = resp.split("\n", 1)[1].rsplit("\n", 1)[0]
|
||||
|
||||
@@ -50,7 +50,7 @@ def fetch_llm_trends() -> List[Dict]:
|
||||
|
||||
只输出 JSON,不要其他文字。"""
|
||||
try:
|
||||
resp = call_llm(prompt, temperature=0.4, max_tokens=2000)
|
||||
resp = call_llm(prompt, temperature=0.4)
|
||||
resp = resp.strip()
|
||||
if resp.startswith("```"):
|
||||
resp = resp.split("\n", 1)[1].rsplit("\n", 1)[0]
|
||||
|
||||
@@ -35,21 +35,33 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
_md_parser = mistune.create_markdown()
|
||||
|
||||
PLATFORM_CONFIG = {
|
||||
"zhihu": {
|
||||
"max_chars": 3000,
|
||||
"style": "深度长文分析",
|
||||
},
|
||||
"wechat": {
|
||||
"max_chars": 1500,
|
||||
"style": "亲切口语化",
|
||||
},
|
||||
"xiaohongshu": {
|
||||
"max_chars": 800,
|
||||
"style": "图文笔记,emoji+标签",
|
||||
},
|
||||
_FALLBACK_PLATFORM_CONFIG = {
|
||||
"zhihu": {"max_chars": 3000, "style": "深度长文分析", "min_chars": 1500},
|
||||
"wechat": {"max_chars": 1500, "style": "亲切口语化", "min_chars": 800},
|
||||
"xiaohongshu": {"max_chars": 800, "style": "图文笔记,emoji+标签", "min_chars": 300},
|
||||
}
|
||||
|
||||
def _load_platform_config() -> dict:
|
||||
try:
|
||||
from app.database import SessionLocal
|
||||
from app.models import PlatformConfig
|
||||
db = SessionLocal()
|
||||
configs = db.query(PlatformConfig).all()
|
||||
db.close()
|
||||
result = {}
|
||||
for c in configs:
|
||||
result[c.platform] = {
|
||||
"max_chars": c.max_words or _FALLBACK_PLATFORM_CONFIG.get(c.platform, {}).get("max_chars", 3000),
|
||||
"style": c.default_format or _FALLBACK_PLATFORM_CONFIG.get(c.platform, {}).get("style", "深度内容"),
|
||||
"min_chars": c.min_words or _FALLBACK_PLATFORM_CONFIG.get(c.platform, {}).get("min_chars", 300),
|
||||
}
|
||||
return result
|
||||
except Exception:
|
||||
pass
|
||||
return dict(_FALLBACK_PLATFORM_CONFIG)
|
||||
|
||||
PLATFORM_CONFIG = _load_platform_config()
|
||||
|
||||
class Writer:
|
||||
def __init__(self, topic_id: str):
|
||||
self.topic_id = topic_id
|
||||
@@ -96,86 +108,97 @@ class Writer:
|
||||
sections.append(current)
|
||||
return sections
|
||||
|
||||
@staticmethod
|
||||
def _clean_markdown(text: str) -> str:
|
||||
lines = text.split('\n')
|
||||
cleaned = []
|
||||
for line in lines:
|
||||
line = re.sub(r'^#{1,6}\s+', '', line)
|
||||
line = re.sub(r'^[\-\*\+]\s+', '', line)
|
||||
line = re.sub(r'^\d+[\.\)]\s+', '', line)
|
||||
line = re.sub(r'\*{1,3}([^*]+)\*{1,3}', r'\1', line)
|
||||
cleaned.append(line)
|
||||
return '\n'.join(cleaned).strip()
|
||||
|
||||
@staticmethod
|
||||
def _is_outline_noise(line: str) -> bool:
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
return True
|
||||
if stripped.startswith('---'):
|
||||
return True
|
||||
if '大纲生成时间' in stripped:
|
||||
return True
|
||||
if stripped.startswith('*大纲'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _expand_section(self, section: Dict) -> str:
|
||||
content = section.get('content', '').strip()
|
||||
if len(content) > 200:
|
||||
return content
|
||||
if HAVE_LLM and len(content) < 150:
|
||||
logger.info(f"使用 LLM 扩写章节: {section['title']}")
|
||||
prompt = f"""你是一个真人写作者+行业观察者,正在写一篇关于「{self.topic['title']}」的文章。现在写「{section['title']}」这一节。
|
||||
prompt = f"""你是一个资深作者,正在写一篇关于「{self.topic['title']}」的文章。请写「{section['title']}」这一节。
|
||||
|
||||
⚠️ 今天日期:{datetime.datetime.now().strftime('%Y年%m月%d日')}。当前年份:{datetime.datetime.now().year}年。
|
||||
今天日期:{datetime.datetime.now().strftime('%Y年%m月%d日')}。
|
||||
|
||||
笔记要点:
|
||||
{content}
|
||||
|
||||
要求(逐条对照,每一条都不能跳过):
|
||||
### 热点与时效
|
||||
- **必须引用{datetime.datetime.now().year-1}-{datetime.datetime.now().year}年最新数据/事件/政策/行业报告**,禁用一切过时数据
|
||||
- 体现当前国内外正在讨论什么、最新的趋势变化
|
||||
- 每个论点必须配一个真实发生的最新案例(附数据来源),严禁使用虚构数据
|
||||
- 写作前先确认:这个数据和案例是否是最近{datetime.datetime.now().year-1}-{datetime.datetime.now().year}年的?
|
||||
【输出要求】
|
||||
输出3-5段纯粹、流畅的段落文字,共400-800字。
|
||||
|
||||
### 独特观点
|
||||
- 有自己的判断和立场,拒绝"车轱辘话"和"正确废话"
|
||||
- 至少提供一个"大多数人没想到"的角度
|
||||
- 宁可尖锐,也不要平庸
|
||||
格式:
|
||||
- 禁止任何标题/列表/格式标记(#、-、*、1.、**等)
|
||||
- 每段3-5句,段间空行分隔
|
||||
- 用「你」或「我们」视角,自然口语化
|
||||
|
||||
### 价值
|
||||
- 回答读者一个具体问题或解决一个困惑
|
||||
- 每段回答一个"所以呢?"——读者看完能带走什么
|
||||
- 结束时读者要有「学到了+想转发」的感觉
|
||||
内容要求(让文章在各平台能被推荐):
|
||||
- 开头直接切入痛点或反常识观点,抓住注意力
|
||||
- 每个观点配具体案例或数据(用「据统计」「调研显示」等),不要空泛说理
|
||||
- 有独特判断和立场,避免正确废话
|
||||
- 回答「所以呢」——读者看完能带走什么
|
||||
- 结尾有情绪感召力,让人想点赞/收藏/转发
|
||||
|
||||
### 真人感
|
||||
- 用「你」或「我们」视角,不要用「我」
|
||||
- 像人在自然说话,不是AI组装文字
|
||||
- 避免「首先」「其次」「总的来说」「综上所述」「值得注意的是」
|
||||
- 段落短,2-4句一段,节奏有变化
|
||||
- 适当用反问或口语化表达
|
||||
|
||||
### SEO
|
||||
- 自然融入1-2个目标搜索词,不生硬堆砌
|
||||
- 第一句包含核心关键词
|
||||
|
||||
### 专业与简洁
|
||||
- 语言精准,不注水,不为了字数凑内容
|
||||
- 200-400字,写到点子上就停
|
||||
|
||||
### 平台推荐友好
|
||||
- 节奏不能平,要有起承转合
|
||||
- 结尾要让人有点赞/收藏/转发的冲动
|
||||
|
||||
直接输出段落正文。"""
|
||||
直接输出段落正文,不要任何附加说明。"""
|
||||
try:
|
||||
expanded = call_llm(prompt, temperature=0.6, max_tokens=1500)
|
||||
if expanded and len(expanded.strip()) > len(content):
|
||||
return expanded.strip()
|
||||
expanded = call_llm(prompt, temperature=0.6)
|
||||
if expanded:
|
||||
cleaned = self._clean_markdown(expanded.strip())
|
||||
if cleaned:
|
||||
return cleaned
|
||||
except Exception as e:
|
||||
logger.warning(f"LLM 扩写失败: {e}")
|
||||
|
||||
# Fallback: 将 bullet points 展开为段落
|
||||
lines = [l.strip() for l in content.split('\n') if l.strip()]
|
||||
# Fallback: 将 bullet points 展开为段落(过滤噪音行)
|
||||
lines = [l.strip() for l in content.split('\n') if not self._is_outline_noise(l)]
|
||||
if lines:
|
||||
sentences = []
|
||||
for line in lines:
|
||||
text = line.lstrip('- *').strip()
|
||||
text = line
|
||||
for prefix in ['- ', '* ', '1. ', '2. ', '3. ', '4. ', '5. ']:
|
||||
if line.startswith(prefix):
|
||||
text = line[len(prefix):]
|
||||
break
|
||||
text = text.strip()
|
||||
if text:
|
||||
for prefix in ['- ', '* ', '1. ', '2. ', '3. ', '4. ', '5. ']:
|
||||
if line.startswith(prefix):
|
||||
text = line[len(prefix):]
|
||||
break
|
||||
if text[-1] not in '。!?;':
|
||||
text += '。'
|
||||
sentences.append(text)
|
||||
if sentences:
|
||||
return ' '.join(sentences)
|
||||
return content
|
||||
return ''
|
||||
|
||||
def generate_full_markdown(self) -> str:
|
||||
sections = self._parse_outline_sections()
|
||||
parts = []
|
||||
for sec in sections:
|
||||
if sec['level'] == 1:
|
||||
if sec.get('content'):
|
||||
expanded = self._expand_section(sec)
|
||||
if expanded:
|
||||
parts.append(expanded + "\n")
|
||||
continue
|
||||
heading = f"{'#' * sec['level']} {sec['title']}"
|
||||
parts.append(heading)
|
||||
@@ -246,7 +269,7 @@ class Writer:
|
||||
if HAVE_LLM:
|
||||
prompt = tag_prompts.get(platform, f"根据文章信息生成适合{platform}的标签。标题:{title} 领域:{field} 核心观点:{core} 直接输出标签,空格分隔。")
|
||||
try:
|
||||
tags_text = call_llm(prompt, temperature=0.2, max_tokens=1000)
|
||||
tags_text = call_llm(prompt, temperature=0.2)
|
||||
if tags_text:
|
||||
tags = [t.strip('#') for t in tags_text.strip().split() if t.strip('#')]
|
||||
if tags:
|
||||
@@ -342,7 +365,7 @@ class Writer:
|
||||
|
||||
prompt = title_templates.get(platform, f"给以下文章改个吸引人的{platform}标题:{original}")
|
||||
try:
|
||||
resp = call_llm(prompt, temperature=0.7, max_tokens=1000)
|
||||
resp = call_llm(prompt, temperature=0.7)
|
||||
titles = []
|
||||
for line in resp.strip().split('\n'):
|
||||
line = line.strip()
|
||||
|
||||