从 0 到 1:用 Python + AI 搭建一个“自动写日报”的工具(源码开放)
courier.py这个工具虽然简单,但它涵盖了数据采集 -> 提示词工程 -> AI 交互 -> 自动化集成的完整闭环。不要让你的大脑被低价值的重复劳动占据。程序员的每一行代码,都应该是为了解决问题,包括解决“不想写日报”这个问题。你可以尝试把这个脚本封装成一个 CLI 工具(使用Typer或Click),甚至打包成.exe分享给你的同事(收他们 50 块钱奶茶费,不过分吧?
0. 序章:为了不想写日报,我写了个代码
如果是程序员最讨厌的事情排行榜,“写日报/周报”绝对能进前三。
每天晚上 6 点,当你刚刚解决完一个复杂的并发 Bug,大脑还在回味代码的优雅时,钉钉/飞书弹出一个提醒:“请提交今日日报”。
瞬间,你的大脑一片空白。
“我今天干啥了?”
“上午好像在修环境?”
“下午那个 Bug 到底改了哪里?”
最后,你只能打开 Git Log,一行行复制粘贴,凑出一篇流水账。
这是对生命极大的浪费。
作为一名极客,我们的原则是:凡是超过三次的重复劳动,都应该自动化。
今天,我将带你从零开始,用 Python + Git Log + LLM (大模型) 搭建一个**“全自动日报生成器”**。它不仅能自动读取你的代码提交记录,还能利用 AI 的润色能力,把破碎的提交信息通过“STAR 原则”美化成一份让老板无可挑剔的专业日报,并自动推送到工作群。
Ⅰ. 架构设计:把“流水账”变成“奏折”
我们不能只是简单地把 Git Log 扔给老板,那是“数据”,不是“信息”。我们需要一个加工厂。
这个工具的核心逻辑(Pipeline)非常清晰,是一个典型的 RAG(检索增强生成) 的微型应用:
- 数据层 (Miner): 从你的本地代码仓库挖掘当天的“工作痕迹”(Git Commits)。
- 组装层 (Assembler): 将这些痕迹清洗、去重,并拼接成 AI 能读懂的 Prompt。
- 大脑层 (Brain): 调用 LLM API (OpenAI/DeepSeek/Gemini),让 AI 根据预设的人设(Senior Engineer)进行润色。
- 触达层 (Courier): 将生成的 Markdown 报告推送到飞书/钉钉机器人。
系统架构图
Ⅱ. 数据挖掘:不要欺骗自己,Git 不会撒谎
日报写不出来,本质是上下文丢失。而 Git Commit Log 是最诚实的记录者。我们需要编写一个 Python 脚本,自动提取当前用户、今天的所有提交。
2.1 核心依赖
我们需要 gitpython 来操作 Git,requests 来调用 API。
pip install gitpython requests openai
2.2 挖掘机代码实现 (miner.py)
这个模块负责深入你的项目目录,把今天的提交挖出来。
import os
from datetime import datetime, time
from git import Repo, InvalidGitRepositoryError
class GitMiner:
def __init__(self, repo_paths, author_name):
"""
:param repo_paths: list, 项目路径列表(支持多项目监控)
:param author_name: str, 你的 Git 用户名,防止把同事的提交算进去
"""
self.repo_paths = repo_paths
self.author_name = author_name
def get_daily_commits(self):
daily_logs = []
today = datetime.now().date()
# 定义今天的起止时间
start_of_day = datetime.combine(today, time.min)
end_of_day = datetime.combine(today, time.max)
print(f"🕵️ 正在挖掘 {today} 的代码提交...")
for path in self.repo_paths:
try:
repo = Repo(path)
# 检查是否有当天提交
for commit in repo.iter_commits():
# 提交时间转 datetime
commit_date = datetime.fromtimestamp(commit.committed_date)
# 过滤条件:必须是今天,且必须是本人
if (start_of_day <= commit_date <= end_of_day) and \
(self.author_name in commit.author.name):
# 提取关键信息:Hash前7位 + 提交信息
log_entry = f"[{repo.working_dir.split('/')[-1]}] {commit.hexsha[:7]} - {commit.message.strip()}"
daily_logs.append(log_entry)
# 优化:如果遍历到昨天的提交,直接中断当前仓库的循环(Git log 是倒序的)
if commit_date < start_of_day:
break
except InvalidGitRepositoryError:
print(f"⚠️ 警告: {path} 不是一个有效的 Git 仓库,已跳过。")
continue
return daily_logs
if __name__ == "__main__":
# 测试代码
miner = GitMiner(
repo_paths=["/Users/admin/Work/ProjectA", "/Users/admin/Work/ProjectB"],
author_name="JackMa"
)
logs = miner.get_daily_commits()
print("\n".join(logs))
避坑指南:很多时候我们会在多个项目间切换。所以
repo_paths设计为列表,支持一次性扫描所有正在开发的项目。
Ⅲ. AI 炼金术:Prompt Engineering 是核心
如果你直接把 Git Log 扔给 AI 说“帮我写个日报”,它大概率会给你写出一堆废话。我们需要通过 Prompt 让 AI 扮演一个**“高情商、懂技术的资深工程师”**。
我们需要 AI 做三件事:
- 归纳: 把琐碎的
fix bug合并成一个完整的功能点。 - 润色: 把
修改了空指针变成优化系统稳定性,修复潜在的空指针异常(听起来就贵了 2000 块)。 - 排版: 输出符合 Markdown 格式的列表。
3.1 定义 Prompt 模板 (prompt_manager.py)
SYSTEM_PROMPT = """
你是一名资深软件工程师,擅长向上管理和工作汇报。
你的任务是根据用户提供的 Git Commit Logs,生成一份高质量的“每日工作汇报”。
要求:
1. **结构清晰**:使用 STAR 原则(Situation, Task, Action, Result)重新组织语言。
2. **语气专业**:不要使用流水账口吻,要体现技术深度和业务价值。
3. **合并同类项**:如果有多条 Commit 属于同一个功能开发,请合并为一条汇报。
4. **格式规范**:输出 Markdown 格式,包含【今日工作内容】、【遇到的问题与解决】(如果Log里体现了Bug fix)、【明日计划】(根据今日内容推测)。
5. **拒绝废话**:保持简洁有力。
"""
USER_TEMPLATE = """
这是我今天的 Git 提交记录:
{git_logs}
请帮我生成日报。
"""
Ⅳ. 核心引擎:接入 LLM (brain.py)
这里我们使用 OpenAI SDK,你可以随意替换为 DeepSeek、Moonshot 或本地 Ollama 的 API 地址。
from openai import OpenAI
from prompt_manager import SYSTEM_PROMPT, USER_TEMPLATE
class AIBrain:
def __init__(self, api_key, base_url="https://api.openai.com/v1", model="gpt-3.5-turbo"):
self.client = OpenAI(api_key=api_key, base_url=base_url)
self.model = model
def generate_report(self, git_logs):
if not git_logs:
return "🤖 经过检测,你今天似乎没有提交任何代码... 是在摸鱼,还是在做架构设计?(建议手动补充)"
# 拼接 raw string
raw_logs = "\n".join(git_logs)
try:
print("🧠 AI 正在疯狂思考如何美化你的工作...")
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": USER_TEMPLATE.format(git_logs=raw_logs)}
],
temperature=0.7 # 稍微有点创造力,但别太离谱
)
return response.choices[0].message.content
except Exception as e:
return f"❌ AI 罢工了: {str(e)}"
Ⅴ. 最后一公里:自动推送 (courier.py)
生成了文本,复制粘贴还是太累。我们要直接推送到群里。以飞书机器人 (Lark Bot) 为例,钉钉和企业微信同理(都是 Webhook)。
import requests
import json
class FeishuCourier:
def __init__(self, webhook_url):
self.webhook_url = webhook_url
def deliver(self, markdown_content):
headers = {'Content-Type': 'application/json'}
# 飞书机器人的富文本格式
payload = {
"msg_type": "interactive",
"card": {
"header": {
"title": {
"tag": "plain_text",
"content": "📅 自动日报生成"
},
"template": "blue"
},
"elements": [
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": markdown_content
}
},
{
"tag": "hr"
},
{
"tag": "note",
"elements": [
{
"tag": "plain_text",
"content": "Powered by Python & AI 🚀"
}
]
}
]
}
}
try:
res = requests.post(self.webhook_url, headers=headers, data=json.dumps(payload))
if res.status_code == 200:
print("✅ 日报已成功推送到飞书群!")
else:
print(f"⚠️ 推送失败: {res.text}")
except Exception as e:
print(f"❌ 网络错误: {e}")
Ⅵ. 完整组装与运行 (main.py)
现在,我们将所有模块组装在一起,构成最终的执行脚本。
import os
from dotenv import load_dotenv
from miner import GitMiner
from brain import AIBrain
from courier import FeishuCourier
# 加载环境变量 (API Key 等敏感信息)
load_dotenv()
# 配置区
CONFIG = {
"REPO_PATHS": [
"/Users/yourname/project/backend",
"/Users/yourname/project/frontend"
],
"AUTHOR_NAME": "YourGitName",
"LLM_API_KEY": os.getenv("LLM_API_KEY"),
"LLM_BASE_URL": os.getenv("LLM_BASE_URL", "https://api.openai.com/v1"),
"LLM_MODEL": "gpt-3.5-turbo",
"WEBHOOK_URL": os.getenv("FEISHU_WEBHOOK")
}
def main():
# 1. 挖掘
miner = GitMiner(CONFIG["REPO_PATHS"], CONFIG["AUTHOR_NAME"])
logs = miner.get_daily_commits()
print(f"📊 共扫描到 {len(logs)} 条今日提交。")
# 2. 思考
brain = AIBrain(CONFIG["LLM_API_KEY"], CONFIG["LLM_BASE_URL"], CONFIG["LLM_MODEL"])
report = brain.generate_report(logs)
print("-" * 30)
print(report) # 在控制台先预览一下
print("-" * 30)
# 3. 发送 (增加一个确认步骤,防止 AI胡说八道直接发群里)
confirm = input("🚀 是否推送到群里? (y/n): ")
if confirm.lower() == 'y':
courier = FeishuCourier(CONFIG["WEBHOOK_URL"])
courier.deliver(report)
else:
print("已取消发送。")
if __name__ == "__main__":
main()
Ⅶ. 进阶玩法:让它更聪明
上面的版本已经能用了,但作为一个有追求的架构师,我们还可以加入更多功能:
7.1 加入日历上下文 (Context)
代码只是工作的一部分。有时候我们一整天都在开会。
思路: 接入 Google Calendar API 或 读取本地 .todo 文件。
在 Prompt 中增加一段:另外,这是我今天的日历事项:{calendar_events}。如果代码提交很少,请结合会议内容侧重描述方案设计和沟通。
7.2 隐私保护与脱敏
直接把公司源码的 Commit Message 发给 OpenAI 可能存在合规风险。
优化: 在 GitMiner 中加入正则过滤,把敏感的 IP、Token、内部项目代号自动替换为 ***。或者使用本地部署的 Llama 3 或 Qwen 模型,确保数据不出内网。
7.3 定时自动触发
虽然手动跑脚本很爽,但我们希望更懒。
Mac/Linux 用户可以使用 Crontab:
# 每天下午 18:30 自动运行
30 18 * * 1-5 /usr/bin/python3 /path/to/main.py >> /tmp/report.log
Ⅷ. 总结
这个工具虽然简单,但它涵盖了 数据采集 -> 提示词工程 -> AI 交互 -> 自动化集成 的完整闭环。
它带来的价值不仅仅是每天省下的 10 分钟,更是一种思维方式的转变:不要让你的大脑被低价值的重复劳动占据。
程序员的每一行代码,都应该是为了解决问题,包括解决“不想写日报”这个问题。
下一步: 你可以尝试把这个脚本封装成一个 CLI 工具(使用 Typer 或 Click),甚至打包成 .exe 分享给你的同事(收他们 50 块钱奶茶费,不过分吧?)。
更多推荐

所有评论(0)