- Add AI学习助手 agent creation script with all 39 tools, 3-layer KG+RAG memory - Add renshenguo (人参果) feishu bot integration (app_service + ws_handler) - Register renshenguo WS client in main.py startup - Add RENSHENGUO_APP_ID / RENSHENGUO_APP_SECRET / RENSHENGUO_AGENT_ID config - Reorganize docs from root into docs/ subdirectories - Move startup scripts to scripts/startup/ - Various backend optimizations and tool improvements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
404 lines
14 KiB
Python
404 lines
14 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
===========================================
|
||
📋 每日工作总结自动生成器
|
||
功能:每天早上9点 → 生成今日工作总结 → 推送到指定渠道
|
||
===========================================
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import sys
|
||
import datetime
|
||
import smtplib
|
||
import requests
|
||
from email.mime.text import MIMEText
|
||
from email.mime.multipart import MIMEMultipart
|
||
from pathlib import Path
|
||
|
||
# ===========================================
|
||
# 📝 第一部分:配置区(请按需修改)
|
||
# ===========================================
|
||
|
||
class Config:
|
||
"""所有配置集中管理,方便修改"""
|
||
|
||
# --- 数据来源方式 ---
|
||
# mode = "manual" → 手动输入今日事项
|
||
# mode = "file" → 从文件读取今日事项
|
||
DATA_MODE = "manual"
|
||
|
||
# 当 DATA_MODE = "file" 时,读取此文件
|
||
DATA_FILE = "today_work_items.txt"
|
||
|
||
# --- 推送方式(可多选)---
|
||
# 支持:wecom(企业微信)、dingtalk(钉钉)、email(邮件)
|
||
PUSH_CHANNELS = ["wecom"] # 可改为 ["dingtalk"] 或 ["email"]
|
||
|
||
# ----- 企业微信机器人 -----
|
||
WECOM_WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY_HERE"
|
||
|
||
# ----- 钉钉机器人 -----
|
||
DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN_HERE"
|
||
|
||
# ----- 邮件配置 -----
|
||
SMTP_SERVER = "smtp.qq.com"
|
||
SMTP_PORT = 465
|
||
SMTP_USER = "your_email@qq.com"
|
||
SMTP_PASSWORD = "your_auth_code" # 邮件授权码,非密码
|
||
MAIL_TO = ["boss@company.com", "yourself@company.com"]
|
||
|
||
# --- 总结模板 ---
|
||
SUMMARY_TEMPLATE = """
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
📅 今日工作总结 · {date}
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
|
||
👤 姓名:{name}
|
||
🏢 部门:{department}
|
||
|
||
📌 今日工作事项:
|
||
{work_items}
|
||
|
||
📊 工作总结:
|
||
{summary}
|
||
|
||
✅ 明日计划:
|
||
{tomorrow_plan}
|
||
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
⏰ 生成时间:{generate_time}
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
"""
|
||
|
||
|
||
# ===========================================
|
||
# 🔧 第二部分:核心功能
|
||
# ===========================================
|
||
|
||
class WorkSummaryGenerator:
|
||
"""工作总结生成器"""
|
||
|
||
def __init__(self, name="张三", department="技术部"):
|
||
self.name = name
|
||
self.department = department
|
||
self.today = datetime.date.today()
|
||
self.tomorrow = self.today + datetime.timedelta(days=1)
|
||
|
||
def get_work_items_from_input(self):
|
||
"""方式一:手动输入今日工作事项"""
|
||
print("\n📝 请输入你今天的工作事项(每行一条,输入空行结束):")
|
||
print("(例:完成了XX功能开发 / 修复了XXbug / 参加了XX会议)\n")
|
||
items = []
|
||
while True:
|
||
line = input(" ➜ ").strip()
|
||
if not line:
|
||
break
|
||
items.append(line)
|
||
return items
|
||
|
||
def get_work_items_from_file(self, filepath):
|
||
"""方式二:从文件读取今日工作事项"""
|
||
try:
|
||
with open(filepath, "r", encoding="utf-8") as f:
|
||
items = [line.strip() for line in f if line.strip()]
|
||
return items
|
||
except FileNotFoundError:
|
||
print(f"⚠️ 文件 {filepath} 不存在,请先创建!")
|
||
return []
|
||
|
||
def generate_summary(self, work_items):
|
||
"""生成工作总结(基于规则+模板,你也可以接入AI API)"""
|
||
if not work_items:
|
||
return "今日暂无工作记录。"
|
||
|
||
# 统计信息
|
||
total_items = len(work_items)
|
||
|
||
# 简单分类统计(关键词匹配)
|
||
categories = {
|
||
"开发": 0, "修复": 0, "会议": 0, "文档": 0,
|
||
"测试": 0, "沟通": 0, "其他": 0
|
||
}
|
||
keywords_map = {
|
||
"开发": ["开发", "编码", "编程", "实现", "搭建", "构建"],
|
||
"修复": ["修复", "解决", "处理", "修改", "bug", "Bug"],
|
||
"会议": ["会议", "评审", "讨论", "沟通会", "晨会", "周会"],
|
||
"文档": ["文档", "文档", "方案", "设计", "PPT", "报告"],
|
||
"测试": ["测试", "调试", "自测", "联调", "验证"],
|
||
"沟通": ["沟通", "对齐", "同步", "协调", "对接"],
|
||
}
|
||
|
||
for item in work_items:
|
||
matched = False
|
||
for cat, keywords in keywords_map.items():
|
||
if any(kw in item for kw in keywords):
|
||
categories[cat] += 1
|
||
matched = True
|
||
break
|
||
if not matched:
|
||
categories["其他"] += 1
|
||
|
||
# 生成总结文本
|
||
summary_parts = [f"今日共完成 {total_items} 项工作,具体如下:\n"]
|
||
|
||
# 分类汇总
|
||
active_cats = {k: v for k, v in categories.items() if v > 0}
|
||
if active_cats:
|
||
summary_parts.append("📊 工作类型分布:")
|
||
for cat, count in active_cats.items():
|
||
bar = "█" * count
|
||
summary_parts.append(f" {cat}:{bar} {count}项")
|
||
summary_parts.append("")
|
||
|
||
# 逐项列出
|
||
summary_parts.append("📋 详细工作记录:")
|
||
for i, item in enumerate(work_items, 1):
|
||
summary_parts.append(f" {i}. {item}")
|
||
|
||
# 评价与建议
|
||
summary_parts.append(f"\n💡 今日小结:今日工作效率{'较高' if total_items >= 5 else '正常'},"
|
||
f"建议明日继续保持{'/优化时间管理' if total_items < 3 else ''}。")
|
||
|
||
return "\n".join(summary_parts)
|
||
|
||
def generate_tomorrow_plan(self):
|
||
"""生成明日计划(可扩展为从配置文件读取)"""
|
||
plan_items = [
|
||
"继续推进当前开发任务",
|
||
"同步项目进度",
|
||
"代码审查",
|
||
]
|
||
return "\n".join(f" {i+1}. {item}" for i, item in enumerate(plan_items))
|
||
|
||
def build_summary_text(self, work_items, summary):
|
||
"""组装完整的总结文本"""
|
||
tomorrow_plan = self.generate_tomorrow_plan()
|
||
formatted_items = "\n".join(f" • {item}" for item in work_items)
|
||
|
||
now_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
|
||
return Config.SUMMARY_TEMPLATE.format(
|
||
date=self.today.strftime("%Y年%m月%d日"),
|
||
name=self.name,
|
||
department=self.department,
|
||
work_items=formatted_items if formatted_items else " (暂无记录)",
|
||
summary=summary,
|
||
tomorrow_plan=tomorrow_plan,
|
||
generate_time=now_str
|
||
)
|
||
|
||
def run(self):
|
||
"""主运行流程"""
|
||
print(f"\n{'='*50}")
|
||
print(f"📅 今日工作总结生成器")
|
||
print(f"📆 {self.today.strftime('%Y年%m月%d日')}")
|
||
print(f"{'='*50}\n")
|
||
|
||
# 1️⃣ 获取工作事项
|
||
if Config.DATA_MODE == "file":
|
||
items = self.get_work_items_from_file(Config.DATA_FILE)
|
||
else:
|
||
items = self.get_work_items_from_input()
|
||
|
||
if not items:
|
||
print("⚠️ 没有输入任何工作事项,将生成空总结。")
|
||
|
||
# 2️⃣ 生成总结
|
||
summary = self.generate_summary(items)
|
||
final_text = self.build_summary_text(items, summary)
|
||
|
||
# 3️⃣ 本地保存
|
||
self.save_to_file(final_text)
|
||
|
||
# 4️⃣ 推送
|
||
pusher = MessagePusher()
|
||
pusher.push(final_text)
|
||
|
||
return final_text
|
||
|
||
def save_to_file(self, content):
|
||
"""保存到本地文件"""
|
||
filename = f"工作总结_{self.today.strftime('%Y%m%d')}.md"
|
||
with open(filename, "w", encoding="utf-8") as f:
|
||
f.write(content)
|
||
print(f"\n✅ 已保存到本地文件:{os.path.abspath(filename)}")
|
||
|
||
|
||
# ===========================================
|
||
# 📨 第三部分:消息推送
|
||
# ===========================================
|
||
|
||
class MessagePusher:
|
||
"""消息推送器"""
|
||
|
||
def push(self, content):
|
||
"""根据配置推送消息到各个渠道"""
|
||
for channel in Config.PUSH_CHANNELS:
|
||
if channel == "wecom":
|
||
self.push_wecom(content)
|
||
elif channel == "dingtalk":
|
||
self.push_dingtalk(content)
|
||
elif channel == "email":
|
||
self.push_email(content)
|
||
else:
|
||
print(f"⚠️ 未知推送渠道: {channel}")
|
||
|
||
def push_wecom(self, content):
|
||
"""推送到企业微信机器人"""
|
||
url = Config.WECOM_WEBHOOK
|
||
if "YOUR_KEY_HERE" in url:
|
||
print("⚠️ 跳过企业微信推送:未配置Webhook地址")
|
||
return
|
||
|
||
data = {
|
||
"msgtype": "markdown",
|
||
"markdown": {"content": content}
|
||
}
|
||
try:
|
||
resp = requests.post(url, json=data, timeout=10)
|
||
result = resp.json()
|
||
if result.get("errcode") == 0:
|
||
print("✅ 企业微信推送成功!")
|
||
else:
|
||
print(f"⚠️ 企业微信推送失败: {result}")
|
||
except Exception as e:
|
||
print(f"⚠️ 企业微信推送异常: {e}")
|
||
|
||
def push_dingtalk(self, content):
|
||
"""推送到钉钉机器人"""
|
||
url = Config.DINGTALK_WEBHOOK
|
||
if "YOUR_TOKEN_HERE" in url:
|
||
print("⚠️ 跳过钉钉推送:未配置Webhook地址")
|
||
return
|
||
|
||
data = {
|
||
"msgtype": "markdown",
|
||
"markdown": {
|
||
"title": "今日工作总结",
|
||
"text": content
|
||
}
|
||
}
|
||
try:
|
||
resp = requests.post(url, json=data, timeout=10)
|
||
result = resp.json()
|
||
if result.get("errcode") == 0:
|
||
print("✅ 钉钉推送成功!")
|
||
else:
|
||
print(f"⚠️ 钉钉推送失败: {result}")
|
||
except Exception as e:
|
||
print(f"⚠️ 钉钉推送异常: {e}")
|
||
|
||
def push_email(self, content):
|
||
"""通过邮件推送"""
|
||
if "your_email" in Config.SMTP_USER:
|
||
print("⚠️ 跳过邮件推送:未配置邮箱信息")
|
||
return
|
||
|
||
try:
|
||
msg = MIMEMultipart()
|
||
msg["From"] = Config.SMTP_USER
|
||
msg["To"] = ", ".join(Config.MAIL_TO)
|
||
msg["Subject"] = f"今日工作总结 - {datetime.date.today().strftime('%Y-%m-%d')}"
|
||
|
||
msg.attach(MIMEText(content, "plain", "utf-8"))
|
||
|
||
with smtplib.SMTP_SSL(Config.SMTP_SERVER, Config.SMTP_PORT) as server:
|
||
server.login(Config.SMTP_USER, Config.SMTP_PASSWORD)
|
||
server.sendmail(Config.SMTP_USER, Config.MAIL_TO, msg.as_string())
|
||
|
||
print("✅ 邮件推送成功!")
|
||
except Exception as e:
|
||
print(f"⚠️ 邮件推送异常: {e}")
|
||
|
||
|
||
# ===========================================
|
||
# 🚀 第四部分:程序入口
|
||
# ===========================================
|
||
|
||
def setup_windows_task():
|
||
"""生成Windows任务计划程序导入脚本"""
|
||
script_path = os.path.abspath(sys.argv[0])
|
||
python_path = sys.executable
|
||
|
||
cmd = f'''@echo off
|
||
echo ========================================
|
||
echo 设置每日9点自动运行工作总结脚本
|
||
echo ========================================
|
||
|
||
REM 请以管理员身份运行此.bat文件
|
||
|
||
schtasks /create /tn "每日工作总结" /tr "{python_path} {script_path}" /sc daily /st 09:00 /f
|
||
|
||
if %errorlevel%==0 (
|
||
echo ✅ 定时任务创建成功!每天早上9:00自动运行。
|
||
) else (
|
||
echo ❌ 创建失败,请尝试以管理员身份运行。
|
||
)
|
||
|
||
pause
|
||
'''
|
||
|
||
bat_path = "setup_windows_task.bat"
|
||
with open(bat_path, "w", encoding="utf-8") as f:
|
||
f.write(cmd)
|
||
print(f"\n📁 Windows定时任务脚本已生成:{os.path.abspath(bat_path)}")
|
||
print(" → 右键点击该文件,选择「以管理员身份运行」即可设置定时任务!")
|
||
|
||
|
||
def setup_linux_cron():
|
||
"""输出Linux crontab配置说明"""
|
||
script_path = os.path.abspath(sys.argv[0])
|
||
python_path = sys.executable
|
||
|
||
print("\n" + "="*50)
|
||
print("🐧 Linux/macOS 定时任务设置(crontab)")
|
||
print("="*50)
|
||
print(f"在终端中执行以下命令添加定时任务:")
|
||
print(f"\n crontab -e")
|
||
print(f"\n然后添加一行:")
|
||
print(f"\n 0 9 * * * {python_path} {script_path}")
|
||
print(f"\n保存退出即可!📌")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
import sys
|
||
|
||
# 检查是否有命令行参数
|
||
if len(sys.argv) > 1:
|
||
arg = sys.argv[1].lower()
|
||
if arg == "--setup-win":
|
||
setup_windows_task()
|
||
sys.exit(0)
|
||
elif arg == "--setup-linux":
|
||
setup_linux_cron()
|
||
sys.exit(0)
|
||
|
||
print("""
|
||
╔══════════════════════════════════════════╗
|
||
║ 🍊 每日工作总结生成器 ║
|
||
║ ║
|
||
║ 用法: ║
|
||
║ python daily_work_summary.py ║
|
||
║ python daily_work_summary.py --setup-win ║
|
||
║ python daily_work_summary.py --setup-linux ║
|
||
╚══════════════════════════════════════════╝
|
||
""")
|
||
|
||
# 运行主程序
|
||
generator = WorkSummaryGenerator(name="张三", department="技术部")
|
||
result = generator.run()
|
||
|
||
print("\n" + "="*50)
|
||
print("🎉 工作总结生成完成!")
|
||
print("="*50)
|
||
|
||
# 生成本地定时任务设置脚本
|
||
if sys.platform == "win32":
|
||
setup_windows_task()
|
||
else:
|
||
setup_linux_cron()
|
||
|
||
print("\n💡 小提示:修改 config.py 中的配置可自定义推送到不同渠道~")
|