From 9fb819704205c778e472370256a6af03e0f723c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:25:53 +0000 Subject: [PATCH] refactor: extract shared feishu alert script + fix error messages + code review fixes Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .github/workflows/push-broadcast.yml | 54 +--------------- .github/workflows/receive-syslog.yml | 27 +------- .github/workflows/sync-login-entry.yml | 27 +------- backend/feishu-bot/ai-chat.js | 6 +- scripts/save-collaboration-log.js | 4 +- scripts/send-feishu-alert.js | 88 ++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 108 deletions(-) create mode 100644 scripts/send-feishu-alert.js diff --git a/.github/workflows/push-broadcast.yml b/.github/workflows/push-broadcast.yml index 6153fbe7..2299c537 100644 --- a/.github/workflows/push-broadcast.yml +++ b/.github/workflows/push-broadcast.yml @@ -52,32 +52,7 @@ jobs: FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }} FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }} ALERT_CHAT_ID: ${{ secrets.FEISHU_ALERT_CHAT_ID }} - run: | - if [ -z "$ALERT_CHAT_ID" ]; then - echo "⚠️ 未配置 FEISHU_ALERT_CHAT_ID,跳过群通知" - exit 0 - fi - node -e " - const https = require('https'); - function post(url, body) { - return new Promise((resolve, reject) => { - const payload = JSON.stringify(body); - const u = new URL(url); - const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: 'POST', - headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } - }, res => { let d=''; res.on('data', c => d+=c); res.on('end', () => resolve(d)); }); - req.on('error', reject); req.write(payload); req.end(); - }); - } - (async () => { - const tokenRes = JSON.parse(await post('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', - { app_id: process.env.FEISHU_APP_ID, app_secret: process.env.FEISHU_APP_SECRET })); - const token = tokenRes.tenant_access_token; - const payload = JSON.stringify({ text: '📡 新广播已推送到飞书文档B\n\n时间: ' + new Date().toISOString() + '\n请查看飞书广播收件箱。' }); - await post('https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id', - JSON.stringify({ receive_id: process.env.ALERT_CHAT_ID, msg_type: 'text', content: payload })); - })().catch(e => console.error(e.message)); - " + run: node scripts/send-feishu-alert.js "push-broadcast" "📡 新广播已推送到飞书文档B,请查看飞书广播收件箱。" || true - name: 🔴 失败告警 → 飞书通知 if: failure() @@ -85,29 +60,4 @@ jobs: FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }} FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }} ALERT_CHAT_ID: ${{ secrets.FEISHU_ALERT_CHAT_ID }} - run: | - if [ -z "$ALERT_CHAT_ID" ]; then - echo "⚠️ 未配置 FEISHU_ALERT_CHAT_ID,跳过告警" - exit 0 - fi - node -e " - const https = require('https'); - function post(url, body) { - return new Promise((resolve, reject) => { - const payload = JSON.stringify(body); - const u = new URL(url); - const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: 'POST', - headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } - }, res => { let d=''; res.on('data', c => d+=c); res.on('end', () => resolve(d)); }); - req.on('error', reject); req.write(payload); req.end(); - }); - } - (async () => { - const tokenRes = JSON.parse(await post('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', - { app_id: process.env.FEISHU_APP_ID, app_secret: process.env.FEISHU_APP_SECRET })); - const token = tokenRes.tenant_access_token; - const payload = JSON.stringify({ text: '🔴 GitHub Action 失败告警\n\n工作流: push-broadcast\n时间: ' + new Date().toISOString() + '\n请检查 GitHub Actions 日志。' }); - await post('https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id', - JSON.stringify({ receive_id: process.env.ALERT_CHAT_ID, msg_type: 'text', content: payload })); - })().catch(e => console.error(e.message)); - " + run: node scripts/send-feishu-alert.js "push-broadcast" diff --git a/.github/workflows/receive-syslog.yml b/.github/workflows/receive-syslog.yml index 788af75b..0e4bc779 100644 --- a/.github/workflows/receive-syslog.yml +++ b/.github/workflows/receive-syslog.yml @@ -58,29 +58,4 @@ jobs: FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }} FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }} ALERT_CHAT_ID: ${{ secrets.FEISHU_ALERT_CHAT_ID }} - run: | - if [ -z "$ALERT_CHAT_ID" ]; then - echo "⚠️ 未配置 FEISHU_ALERT_CHAT_ID,跳过告警" - exit 0 - fi - node -e " - const https = require('https'); - function post(url, body) { - return new Promise((resolve, reject) => { - const payload = JSON.stringify(body); - const u = new URL(url); - const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: 'POST', - headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } - }, res => { let d=''; res.on('data', c => d+=c); res.on('end', () => resolve(d)); }); - req.on('error', reject); req.write(payload); req.end(); - }); - } - (async () => { - const tokenRes = JSON.parse(await post('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', - { app_id: process.env.FEISHU_APP_ID, app_secret: process.env.FEISHU_APP_SECRET })); - const token = tokenRes.tenant_access_token; - const payload = JSON.stringify({ text: '🔴 GitHub Action 失败告警\n\n工作流: receive-syslog\n时间: ' + new Date().toISOString() + '\n请检查 GitHub Actions 日志。' }); - await post('https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id', - JSON.stringify({ receive_id: process.env.ALERT_CHAT_ID, msg_type: 'text', content: payload })); - })().catch(e => console.error(e.message)); - " + run: node scripts/send-feishu-alert.js "receive-syslog" diff --git a/.github/workflows/sync-login-entry.yml b/.github/workflows/sync-login-entry.yml index b6c92e37..02db3b42 100644 --- a/.github/workflows/sync-login-entry.yml +++ b/.github/workflows/sync-login-entry.yml @@ -46,29 +46,4 @@ jobs: FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }} FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }} ALERT_CHAT_ID: ${{ secrets.FEISHU_ALERT_CHAT_ID }} - run: | - if [ -z "$ALERT_CHAT_ID" ]; then - echo "⚠️ 未配置 FEISHU_ALERT_CHAT_ID,跳过告警" - exit 0 - fi - node -e " - const https = require('https'); - function post(url, body) { - return new Promise((resolve, reject) => { - const payload = JSON.stringify(body); - const u = new URL(url); - const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: 'POST', - headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } - }, res => { let d=''; res.on('data', c => d+=c); res.on('end', () => resolve(d)); }); - req.on('error', reject); req.write(payload); req.end(); - }); - } - (async () => { - const tokenRes = JSON.parse(await post('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', - { app_id: process.env.FEISHU_APP_ID, app_secret: process.env.FEISHU_APP_SECRET })); - const token = tokenRes.tenant_access_token; - const payload = JSON.stringify({ text: '🔴 GitHub Action 失败告警\n\n工作流: sync-login-entry\n时间: ' + new Date().toISOString() + '\n请检查 GitHub Actions 日志。' }); - await post('https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id', - JSON.stringify({ receive_id: process.env.ALERT_CHAT_ID, msg_type: 'text', content: payload })); - })().catch(e => console.error(e.message)); - " + run: node scripts/send-feishu-alert.js "sync-login-entry" diff --git a/backend/feishu-bot/ai-chat.js b/backend/feishu-bot/ai-chat.js index 57e42eab..7061aaa9 100644 --- a/backend/feishu-bot/ai-chat.js +++ b/backend/feishu-bot/ai-chat.js @@ -133,7 +133,7 @@ async function callModel(messages, options = {}) { const model = options.model || process.env.MODEL_NAME || DEFAULT_MODEL; if (!apiKey) { - return '⚠️ AI 模型未配置(缺少 MODEL_API_KEY),请联系管理员。'; + return '⚠️ AI 服务暂时不可用,请联系管理员。'; } const url = new URL(apiBase + '/chat/completions'); @@ -163,10 +163,10 @@ async function callModel(messages, options = {}) { // 尝试降级模型 if (result.statusCode === 429 || result.statusCode >= 500) { - return '⚠️ AI 模型暂时不可用(HTTP ' + result.statusCode + '),请稍后重试。'; + return '⚠️ AI 模型暂时不可用,请稍后重试。'; } - return '⚠️ AI 模型调用异常: ' + (result.data.error?.message || JSON.stringify(result.data)); + return '⚠️ AI 模型调用异常,请稍后重试或联系管理员。'; } catch (e) { return '⚠️ AI 模型调用失败: ' + e.message; } diff --git a/scripts/save-collaboration-log.js b/scripts/save-collaboration-log.js index d7b4e9aa..cde23392 100644 --- a/scripts/save-collaboration-log.js +++ b/scripts/save-collaboration-log.js @@ -107,7 +107,9 @@ function main() { d.total_interactions++; if (r.type === 'syslog_collaboration') d.syslog_count++; if (r.type === 'collaboration') d.chat_count++; - d.last_active_at = r.timestamp; + if (!d.last_active_at || r.timestamp > d.last_active_at) { + d.last_active_at = r.timestamp; + } if (r.channel) d.channels_used.add(r.channel); if (r.broadcast_id && r.broadcast_id !== 'UNKNOWN') d.broadcasts_referenced.add(r.broadcast_id); } diff --git a/scripts/send-feishu-alert.js b/scripts/send-feishu-alert.js new file mode 100644 index 00000000..e4c97410 --- /dev/null +++ b/scripts/send-feishu-alert.js @@ -0,0 +1,88 @@ +// scripts/send-feishu-alert.js +// 铸渊 · 飞书告警通知脚本(供 GitHub Actions 工作流调用) +// +// 用法: node scripts/send-feishu-alert.js "工作流名称" "告警内容" +// +// 环境变量: +// FEISHU_APP_ID 飞书应用 App ID +// FEISHU_APP_SECRET 飞书应用 App Secret +// ALERT_CHAT_ID 飞书群 chat_id + +'use strict'; + +const https = require('https'); + +function httpsPost(url, body) { + return new Promise((resolve, reject) => { + const payload = JSON.stringify(body); + const u = new URL(url); + const req = https.request({ + hostname: u.hostname, + port: 443, + path: u.pathname + u.search, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(payload), + }, + }, res => { + let d = ''; + res.on('data', c => d += c); + res.on('end', () => resolve(d)); + }); + req.on('error', reject); + req.write(payload); + req.end(); + }); +} + +async function main() { + const appId = process.env.FEISHU_APP_ID; + const appSecret = process.env.FEISHU_APP_SECRET; + const chatId = process.env.ALERT_CHAT_ID; + const workflow = process.argv[2] || 'unknown'; + const detail = process.argv[3] || ''; + + if (!chatId) { + console.log('⚠️ 未配置 ALERT_CHAT_ID,跳过告警'); + process.exit(0); + } + if (!appId || !appSecret) { + console.log('⚠️ 未配置飞书 App 凭据,跳过告警'); + process.exit(0); + } + + // 获取飞书 token + const tokenRes = JSON.parse(await httpsPost( + 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', + { app_id: appId, app_secret: appSecret } + )); + const token = tokenRes.tenant_access_token; + if (!token) { + console.error('❌ 获取飞书 token 失败'); + process.exit(1); + } + + // 发送消息 + const text = '🔴 GitHub Action 失败告警\n\n' + + '工作流: ' + workflow + '\n' + + '时间: ' + new Date().toISOString() + '\n' + + (detail ? '详情: ' + detail + '\n' : '') + + '请检查 GitHub Actions 日志。'; + + await httpsPost( + 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id', + { + receive_id: chatId, + msg_type: 'text', + content: JSON.stringify({ text }), + } + ); + + console.log('✅ 告警已发送到飞书群'); +} + +main().catch(e => { + console.error('❌ 告警发送失败:', e.message); + process.exit(1); +});