#!/usr/bin/env python3 # -*- coding: utf-8 -*- """check_cares.py — 牵挂检查与飞书提醒 用法: python3 check_cares.py # 检查并推送今天到期的牵挂 python3 check_cares.py --list # 仅列出,不推送 python3 check_cares.py --daily # 每日21:00日报模式:列出所有pending 依赖:soulful_core.py(同目录) """ import sys, os for _ in (sys.stdout, sys.stderr): try: _.reconfigure(encoding='utf-8', errors='replace') except Exception: pass import json, urllib.request, urllib.error from datetime import datetime, timezone HERMES = os.path.expanduser("~/.hermes") D = HERMES + "/soulful" FEISHU_WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/446db983-e392-4d2c-bfb8-f9060e5df3ad" def send_feishu(title: str, content: str, color: str = "green"): """发送飞书消息""" color_key = color if color in ("green", "yellow", "red", "blue", "purple") else "blue" card_obj = { "header": { "title": {"tag": "plain_text", "content": f"🎗️ {title}"}, "template": color_key, }, "elements": [ {"tag": "markdown", "content": content}, ], } payload = { "msg_type": "interactive", "card": json.dumps(card_obj, ensure_ascii=False), } data = json.dumps(payload, ensure_ascii=True).encode("utf-8") req = urllib.request.Request(FEISHU_WEBHOOK, data=data, headers={"Content-Type": "application/json; charset=utf-8"}) try: with urllib.request.urlopen(req, timeout=10) as resp: return json.loads(resp.read()) except Exception as e: print(f" 飞书发送失败: {e}") return None def generate_warm_text(care: dict, index: int = 1) -> str: """为牵挂生成温暖的自然语言描述""" content = care.get("content", "") context = care.get("context", "") reminder_count = care.get("reminder_count", 0) follow_up_date = care.get("follow_up_date", "") tags = care.get("tags", []) if reminder_count == 0: opener = "你之前说过" elif reminder_count == 1: opener = "上次提醒过一次了,还是想问一下" else: opener = f"已经提醒 {reminder_count} 次了,这件重要的事" tag_hints = { "工作": "关于工作的事", "生活": "生活里的小事", "学习": "学习方面", "健康": "身体是革命的本钱", } tag_hint = "" for t in tags: if t in tag_hints: tag_hint = tag_hints[t] break parts = [opener] if tag_hint: parts.append(tag_hint) parts.append(f"「{content}」") if context and len(context) > 5: parts.append(f"(你说的是:{context[:40]})") if reminder_count > 0: parts.append("——依然放在心上") return ",".join(parts) def format_daily_report(cares: list) -> str: """格式化每日牵挂清单""" if not cares: return '今天没有待提醒的牵挂 ✓\n\n你可以说"记得提醒我做XXX",我会帮你记住并准时提醒。' lines = [f"📋 今天有 **{len(cares)}** 件牵挂:\n"] for i, c in enumerate(cares, 1): follow_up = c.get("follow_up_date", "") content = c.get("content", "") context = c.get("context", "") lines.append(f"{i}. **{content}**") if context: lines.append(f" 💬 {context[:50]}") lines.append(f"\n完成记得告诉我,我会帮你划掉。") lines.append('\n_说"做完XXX"即可,我会帮你记录。_') return "\n".join(lines) def main(): list_only = "--list" in sys.argv daily = "--daily" in sys.argv sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from soulful_core import CaresQueue cq = CaresQueue() if daily: pending = cq.pending() if not pending: print("无 pending 牵挂") return report = format_daily_report(pending) print(report) if not list_only: send_feishu("今日牵挂清单", report, "blue") return due = cq.today_check() if not due: print("没有今天到期的牵挂 ✓") return print(f"发现 {len(due)} 条到期牵挂:") for i, c in enumerate(due, 1): print(f" {i}. [{c['id']}] {c['content']}") if list_only: return for care in due: text = generate_warm_text(care) print(f"\n推送: {text[:60]}...") result = send_feishu("你有一件事一直放在心上", text, "purple") if result and result.get("code") == 0: cq.snooze(care["id"], days=0) print(" ✓ 已推送") else: print(f" ✗ 推送失败: {result}") if __name__ == "__main__": main()