From f015b72ad877edfd21f286e05c8fc7392ebe2feb Mon Sep 17 00:00:00 2001 From: mac Date: Thu, 4 Jun 2026 12:46:00 +0800 Subject: [PATCH] =?UTF-8?q?v1.3.1=20=E2=80=94=20=E6=97=A5=E5=8E=86?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=94=B9=E4=B8=BA=E5=AE=9E=E6=97=B6=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E9=92=89=E9=92=89=20MCP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端直接调用钉钉 MCP Gateway (JSON-RPC) - 返回结果同时写入缓存,MCP 不可用时回退缓存 - 无需定时任务,点击即查 --- app.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/app.py b/app.py index f54b1dc..83be079 100644 --- a/app.py +++ b/app.py @@ -228,22 +228,84 @@ def api_reorder_wishes(): # ── 日历同步 API ──────────────────────────── CALENDAR_CACHE = os.path.join(os.path.expanduser('~'), '.workbuddy', 'data', 'ziwei-power', 'calendar_cache.json') +DING_MCP_URL = 'https://mcp-gw.dingtalk.com/server/95959163f85d8b58a167f65cd8bd3d22690b16c75ebacd0fa095016396a10e0d?key=0993e4d4e44c50ea25a0db840cc5815e' + + +def _fetch_dingtalk_events(date_str): + """调用钉钉 MCP 实时查询指定日期的日程""" + import json as _json, urllib.request as _ur + from datetime import datetime, timezone, timedelta + tz = timezone(timedelta(hours=8)) + try: + d = datetime.strptime(date_str, '%Y-%m-%d').replace(tzinfo=tz) + except ValueError: + return [] + start_ts = int(d.replace(hour=0, minute=0, second=0).timestamp() * 1000) + end_ts = int(d.replace(hour=23, minute=59, second=59).timestamp() * 1000) + body = _json.dumps({ + 'jsonrpc': '2.0', 'method': 'tools/call', 'id': 1, + 'params': {'name': 'list_calendar_events', 'arguments': { + 'calendarId': 'primary', 'startTime': start_ts, 'endTime': end_ts, 'limit': 20 + }} + }).encode('utf-8') + req = _ur.Request(DING_MCP_URL, data=body, headers={ + 'Content-Type': 'application/json', 'Accept': 'application/json' + }) + try: + with _ur.urlopen(req, timeout=10) as resp: + data = _json.loads(resp.read()) + events = data.get('result', {}).get('structuredContent', {}).get('result', {}).get('events', []) + except Exception: + return None # 网络错误返回 None,调用方回退缓存 + results = [] + for e in events: + summary = (e.get('summary') or '').strip() + if not summary: + continue + start = e.get('start', {}).get('dateTime', '') + end = e.get('end', {}).get('dateTime', '') + time_str = '' + if start and end: + time_str = start[11:16] + '-' + end[11:16] + results.append({ + 'date': date_str, 'summary': summary, + 'time': time_str, 'location': e.get('location') or '' + }) + # 写入缓存 + try: + all_cached = [] + try: + with open(CALENDAR_CACHE, 'r') as f: + all_cached = _json.load(f) + except (FileNotFoundError, _json.JSONDecodeError): + pass + # 替换同一天的旧缓存 + all_cached = [c for c in all_cached if c.get('date') != date_str] + results + with open(CALENDAR_CACHE, 'w') as f: + _json.dump(all_cached, f, ensure_ascii=False, indent=2) + except Exception: + pass + return results + @app.route('/api/calendar-sync', methods=['GET']) @login_required def api_calendar_sync(): - """获取指定日期的钉钉日历会议""" import json as _json date = request.args.get('date', '') if not date: return jsonify({'ok': False, 'error': '缺少 date 参数'}), 400 - try: - with open(CALENDAR_CACHE, 'r') as f: - events = _json.load(f) - except (FileNotFoundError, _json.JSONDecodeError): - return jsonify({'ok': True, 'data': []}) - today_events = [e for e in events if e.get('date') == date] - return jsonify({'ok': True, 'data': today_events}) + # 优先实时查询钉钉 MCP + events = _fetch_dingtalk_events(date) + if events is None: + # MCP 不可用,回退缓存 + try: + with open(CALENDAR_CACHE, 'r') as f: + all_cached = _json.load(f) + events = [e for e in all_cached if e.get('date') == date] + except (FileNotFoundError, _json.JSONDecodeError): + events = [] + return jsonify({'ok': True, 'data': events}) # ── 启动 ──────────────────────────────────────────────