需要一点个人的小小捣鼓文档的能力…纯水版本,等后面CC的也造出来了,发个一步步版本
config.toml
notify = ["python", "C:/Users/你的用户名/.codex/notify_template.py"]
导入飞书的卡片
新建个CodexCLI项目已完工.card,名字随意,内容
{"name":"CodexCLI 项目已完工","dsl":{"schema":"2.0","config":{"update_multi":true,"style":{"text_size":{"normal_v2":{"default":"normal","pc":"normal","mobile":"heading"}}}},"body":{"direction":"vertical","elements":[{"tag":"markdown","content":"**CodexCLI已完成需求**","margin":"0px 0px 0px 0px","element_id":"Ovh10jYri6DsF7m9U06A"},{"tag":"hr","margin":"0px 0px 0px 0px"},{"tag":"markdown","content":"#### ${title}","text_align":"left","text_size":"normal_v2","margin":"0px 0px 0px 0px"},{"tag":"picker_time","placeholder":{"tag":"plain_text","content":""},"width":"default","initial_time":"${time}","margin":"0px 0px 0px 0px"}]},"header":{"title":{"tag":"plain_text","content":"CodexCLI 已完工"},"subtitle":{"tag":"plain_text","content":""},"text_tag_list":[{"tag":"text_tag","text":{"tag":"plain_text","content":"已完成"},"color":"green"}],"template":"blue","icon":{"tag":"standard_icon","token":"check-circle_outlined"},"padding":"12px 8px 12px 8px"}},"variables":[{"type":"time","apiName":"var_mkly9why","name":"time","desc":"","mockData":"10:04"},{"type":"text","apiName":"var_mkly9wi9","name":"title","desc":"","mockData":"测速"}]}
- 去 飞书卡片搭建工具
记得复制ID给下面用
notify_template.py
import sys
import json
import time
import urllib.request
import urllib.error
# ==================== ⚙️ 核心配置 (请填这里) ====================
# [1] 飞书应用凭证 (自建应用 -> 凭证与基础信息)
# 这次我们填 ID 和 Secret,不填那个会过期的 Token 啦!
APP_ID = ""
APP_SECRET = ""
# [2] 接收人与模板
RECEIVE_ID = "" # 你的 User ID
TEMPLATE_ID = "" # 你的卡片模板 ID
# [3] AI 概括配置
SUMMARY_API_URL = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
SUMMARY_API_KEY = ""
SUMMARY_MODEL = "glm-4-flash-250414"
# ===============================================================
def get_tenant_access_token():
"""
Step 1: 动态获取飞书 Token
文档参考: https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal
"""
url = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal"
headers = {"Content-Type": "application/json; charset=utf-8"}
data = {
"app_id": APP_ID,
"app_secret": APP_SECRET
}
try:
req = urllib.request.Request(url, json.dumps(data).encode('utf-8'), headers)
with urllib.request.urlopen(req, timeout=5) as response:
res_json = json.loads(response.read().decode('utf-8'))
if res_json.get("code") == 0:
# 通常 internal app 使用 tenant_access_token 发消息最稳
return res_json.get("tenant_access_token")
else:
print(f"❌ 获取 Token 失败: {res_json.get('msg')}")
return None
except Exception as e:
return None
def call_summary_ai(last_command, assistant_output):
"""
Step 2: 调用 AI 进行概括
"""
system_prompt = (
"你是一个技术助手。请根据用户的【最后一条指令】和系统的【执行结果】,"
"生成一份简短的中文总结(100字以内)。"
"要求:1. 总结核心改动。 2. 语气轻松,必须包含Emoji (✅, 🔧, 🚀)。 3. 不要废话,直接输出内容。"
)
user_content = f"【用户最后指令】: {last_command}\n【代码执行片段】: {assistant_output[:300]}"
payload = {
"model": SUMMARY_MODEL,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_content}
],
"temperature": 0.5,
"max_tokens": 150
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {SUMMARY_API_KEY}"
}
try:
req = urllib.request.Request(SUMMARY_API_URL, json.dumps(payload).encode('utf-8'), headers)
with urllib.request.urlopen(req, timeout=10) as response:
res_json = json.loads(response.read().decode('utf-8'))
summary = res_json['choices'][0]['message']['content'].strip()
return summary.replace('"', '').replace('\n', ' ')
except Exception as e:
return None
def send_feishu_card(access_token, title_content, time_str):
"""
Step 3: 发送卡片通知 (使用动态 Token)
"""
url = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id"
template_content = {
"type": "template",
"data": {
"template_id": TEMPLATE_ID,
"template_version_name": "1.0.2",
"template_variable": {
"title": title_content,
"time": time_str
}
}
}
body = {
"receive_id": RECEIVE_ID,
"msg_type": "interactive",
"content": json.dumps(template_content)
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}" # 这里用刚才动态获取的 token
}
try:
req = urllib.request.Request(url, json.dumps(body).encode('utf-8'), headers)
with urllib.request.urlopen(req) as response:
print(f"✅ 通知发送成功! Status: {response.status}")
except urllib.error.HTTPError as e:
print(f"❌ 发送消息失败: {e.read().decode('utf-8')}")
except Exception as e:
print(f"❌ 未知错误: {e}")
def main():
# 1. 只有拿到了 Token 才能进行下一步
token = get_tenant_access_token()
if not token:
return # 没 Token 啥也干不了,直接退出
current_time = time.strftime("%H:%M", time.localtime())
# 2. 解析 Codex 参数
raw_json = "{}"
if len(sys.argv) > 1:
raw_json = sys.argv[1]
try:
payload = json.loads(raw_json)
except:
payload = {}
# 3. 提取最后一条指令
input_msgs = payload.get("input-messages", [])
if isinstance(input_msgs, list) and len(input_msgs) > 0:
last_command = str(input_msgs[-1])
elif input_msgs:
last_command = str(input_msgs)
else:
last_command = "未知任务"
assistant_output = payload.get("last-assistant-message", "")
# 4. AI 概括
summary = call_summary_ai(last_command, assistant_output)
final_title = summary if summary else last_command[:100]
# 5. 发送通知
send_feishu_card(token, final_title, current_time)
if __name__ == "__main__":
main()
效果图:




