Merge pull request #99 from qinfendebingshuo/copilot/fix-syslog-pipeline-trigger
Wire up SYSLOG pipeline: Notion write + persona invocation + Feishu push-back
This commit is contained in:
commit
f7207f030d
|
|
@ -0,0 +1,88 @@
|
|||
name: 铸渊 · 广播推送飞书(聊天消息)
|
||||
|
||||
# 独立 workflow:接收广播内容,推送飞书消息卡片到原聊天窗口
|
||||
# 用于自动链路推送失败时的手动兜底,或独立触发推送
|
||||
#
|
||||
# 依赖 Secrets:
|
||||
# PUSH_BROADCAST_TOKEN 广播推送接口鉴权 token
|
||||
#
|
||||
# dispatch payload:
|
||||
# chat_id 飞书聊天窗口 ID(优先)
|
||||
# sender_open_id 发送者飞书 Open ID(备选)
|
||||
# broadcast_title 广播标题
|
||||
# broadcast_content 广播摘要内容
|
||||
# broadcast_url Notion 广播页面链接
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [push-broadcast-feishu]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
chat_id:
|
||||
description: '飞书聊天窗口 ID'
|
||||
required: false
|
||||
sender_open_id:
|
||||
description: '发送者飞书 Open ID'
|
||||
required: false
|
||||
broadcast_title:
|
||||
description: '广播标题'
|
||||
required: true
|
||||
broadcast_content:
|
||||
description: '广播摘要'
|
||||
required: true
|
||||
broadcast_url:
|
||||
description: 'Notion 广播页面链接'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
push-to-feishu:
|
||||
name: 📢 推送广播到飞书聊天
|
||||
runs-on: ubuntu-latest
|
||||
permissions: {}
|
||||
|
||||
steps:
|
||||
- name: 📢 推送广播消息卡片
|
||||
env:
|
||||
PUSH_URL: https://guanghulab.com/webhook/push-broadcast
|
||||
PUSH_TOKEN: ${{ secrets.PUSH_BROADCAST_TOKEN }}
|
||||
CHAT_ID: ${{ github.event.client_payload.chat_id || github.event.inputs.chat_id || '' }}
|
||||
SENDER_OPEN_ID: ${{ github.event.client_payload.sender_open_id || github.event.inputs.sender_open_id || '' }}
|
||||
BROADCAST_TITLE: ${{ github.event.client_payload.broadcast_title || github.event.inputs.broadcast_title || '' }}
|
||||
BROADCAST_CONTENT: ${{ github.event.client_payload.broadcast_content || github.event.inputs.broadcast_content || '' }}
|
||||
BROADCAST_URL: ${{ github.event.client_payload.broadcast_url || github.event.inputs.broadcast_url || '' }}
|
||||
run: |
|
||||
if [ -z "$PUSH_TOKEN" ]; then
|
||||
echo "⚠️ PUSH_BROADCAST_TOKEN 未配置,跳过推送"
|
||||
exit 0
|
||||
fi
|
||||
if [ -z "$CHAT_ID" ] && [ -z "$SENDER_OPEN_ID" ]; then
|
||||
echo "⚠️ 缺少 chat_id 和 sender_open_id,无法推送"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📢 推送广播到飞书..."
|
||||
echo " 标题: $BROADCAST_TITLE"
|
||||
echo " 目标: ${CHAT_ID:-$SENDER_OPEN_ID}"
|
||||
|
||||
HTTP_CODE=$(curl -s -o /tmp/push-response.txt -w "%{http_code}" \
|
||||
-X POST "$PUSH_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "x-push-token: $PUSH_TOKEN" \
|
||||
-d "$(jq -n \
|
||||
--arg chat_id "$CHAT_ID" \
|
||||
--arg sender_open_id "$SENDER_OPEN_ID" \
|
||||
--arg broadcast_title "$BROADCAST_TITLE" \
|
||||
--arg broadcast_content "$BROADCAST_CONTENT" \
|
||||
--arg broadcast_url "$BROADCAST_URL" \
|
||||
'{chat_id: $chat_id, sender_open_id: $sender_open_id, broadcast_title: $broadcast_title, broadcast_content: $broadcast_content, broadcast_url: $broadcast_url}')")
|
||||
|
||||
echo " HTTP 响应: $HTTP_CODE"
|
||||
cat /tmp/push-response.txt 2>/dev/null || true
|
||||
echo ""
|
||||
|
||||
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
||||
echo "✅ 广播已推送到飞书"
|
||||
else
|
||||
echo "❌ 推送失败 (HTTP $HTTP_CODE)"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -5,18 +5,29 @@ on:
|
|||
branches: [main]
|
||||
paths:
|
||||
- 'syslog-inbox/**'
|
||||
workflow_run:
|
||||
workflows: ["铸渊 · 飞书SYSLOG桥接"]
|
||||
types: [completed]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# ── Pipeline A:SYSLOG 读取与处理 ──────────────────────
|
||||
pipeline-a-syslog:
|
||||
name: 📥 Pipeline A · SYSLOG 读取处理
|
||||
if: >-
|
||||
github.event_name != 'workflow_run' ||
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: read
|
||||
outputs:
|
||||
processed_count: ${{ steps.process.outputs.processed_count }}
|
||||
has_syslog: ${{ steps.parse.outputs.has_syslog }}
|
||||
sender_open_id: ${{ steps.parse.outputs.sender_open_id }}
|
||||
chat_id: ${{ steps.parse.outputs.chat_id }}
|
||||
sender_name: ${{ steps.parse.outputs.sender_name }}
|
||||
syslog_file: ${{ steps.parse.outputs.syslog_file }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -33,6 +44,41 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# Step 0: 解析 sender 信息(在 process-syslog.js 归档之前)
|
||||
- name: 📋 解析 SYSLOG sender 信息
|
||||
id: parse
|
||||
run: |
|
||||
LATEST=$(ls -t syslog-inbox/*.json 2>/dev/null | grep -v '.gitkeep' | head -1 || true)
|
||||
if [ -z "$LATEST" ]; then
|
||||
echo "📭 syslog-inbox/ 无待处理文件"
|
||||
echo "has_syslog=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "has_syslog=true" >> "$GITHUB_OUTPUT"
|
||||
echo "syslog_file=$LATEST" >> "$GITHUB_OUTPUT"
|
||||
|
||||
SENDER_OPEN_ID=$(jq -r '.sender_open_id // .sender_id // empty' "$LATEST" 2>/dev/null || true)
|
||||
CHAT_ID=$(jq -r '.chat_id // empty' "$LATEST" 2>/dev/null || true)
|
||||
SENDER_NAME=$(jq -r '.sender_name // empty' "$LATEST" 2>/dev/null || true)
|
||||
|
||||
echo "sender_open_id=$SENDER_OPEN_ID" >> "$GITHUB_OUTPUT"
|
||||
echo "chat_id=$CHAT_ID" >> "$GITHUB_OUTPUT"
|
||||
echo "sender_name=$SENDER_NAME" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "📋 SYSLOG 文件: $LATEST"
|
||||
echo " sender_open_id: ${SENDER_OPEN_ID:-无}"
|
||||
echo " chat_id: ${CHAT_ID:-无}"
|
||||
echo " sender_name: ${SENDER_NAME:-无}"
|
||||
|
||||
# Step 1: 写入 Notion SYSLOG 收件箱
|
||||
- name: 📝 写入 Notion SYSLOG 收件箱
|
||||
if: steps.parse.outputs.has_syslog == 'true'
|
||||
env:
|
||||
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
|
||||
NOTION_DB_SYSLOG: ${{ secrets.NOTION_DB_SYSLOG }}
|
||||
run: node scripts/write-notion-syslog.js "${{ steps.parse.outputs.syslog_file }}"
|
||||
|
||||
# Step 2: 处理 syslog-inbox 条目(归档到 syslog-processed/)
|
||||
- name: 📥 处理 syslog-inbox 条目
|
||||
id: process
|
||||
run: |
|
||||
|
|
@ -48,6 +94,143 @@ jobs:
|
|||
git diff --staged --quiet || git commit -m "📥 syslog: 处理 inbox 条目,更新大脑记忆 [skip ci]"
|
||||
git push
|
||||
|
||||
# ── Pipeline B:Claude API 唤醒人格体 ────────────────────
|
||||
pipeline-b-persona:
|
||||
name: 🧠 Pipeline B · 人格体唤醒
|
||||
runs-on: ubuntu-latest
|
||||
needs: pipeline-a-syslog
|
||||
if: needs.pipeline-a-syslog.outputs.has_syslog == 'true'
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
broadcast_title: ${{ steps.persona.outputs.broadcast_title }}
|
||||
broadcast_url: ${{ steps.persona.outputs.broadcast_url }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
ref: main
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: 🧠 唤醒人格体处理 SYSLOG
|
||||
id: persona
|
||||
env:
|
||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
|
||||
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
||||
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||
SUBMIT_TYPE: syslog
|
||||
SYSLOG_FILE: ${{ needs.pipeline-a-syslog.outputs.syslog_file }}
|
||||
AUTHOR: ${{ needs.pipeline-a-syslog.outputs.sender_name }}
|
||||
run: |
|
||||
if [ -z "$LLM_API_KEY" ] || [ -z "$LLM_BASE_URL" ]; then
|
||||
echo "⚠️ LLM_API_KEY 或 LLM_BASE_URL 未配置,跳过人格体唤醒"
|
||||
echo "broadcast_title=" >> "$GITHUB_OUTPUT"
|
||||
echo "broadcast_url=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 读取 SYSLOG 文件内容传递给 wake-persona.js
|
||||
# 注意:Pipeline A 可能已将文件从 syslog-inbox/ 归档到 syslog-processed/
|
||||
if [ -f "$SYSLOG_FILE" ]; then
|
||||
export SUBMIT_CONTENT=$(cat "$SYSLOG_FILE")
|
||||
else
|
||||
BASENAME=$(basename "$SYSLOG_FILE")
|
||||
PROCESSED_FILE=$(find syslog-processed/ -name "$BASENAME" -type f 2>/dev/null | head -1)
|
||||
if [ -n "$PROCESSED_FILE" ]; then
|
||||
echo "📂 文件已归档,从 $PROCESSED_FILE 读取"
|
||||
export SUBMIT_CONTENT=$(cat "$PROCESSED_FILE")
|
||||
else
|
||||
echo "⚠️ SYSLOG 文件未找到: $SYSLOG_FILE(inbox 和 processed 均不存在)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$SUBMIT_CONTENT" ]; then
|
||||
echo "⚠️ SUBMIT_CONTENT 为空,跳过人格体唤醒"
|
||||
echo "broadcast_title=" >> "$GITHUB_OUTPUT"
|
||||
echo "broadcast_url=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if node scripts/wake-persona.js; then
|
||||
echo "✅ 人格体唤醒成功"
|
||||
else
|
||||
echo "⚠️ 人格体唤醒失败(exit code: $?),继续后续步骤"
|
||||
fi
|
||||
|
||||
# 读取人格体输出的广播信息(如果有)
|
||||
if [ -f /tmp/broadcast-result.json ]; then
|
||||
BROADCAST_TITLE=$(jq -r '.title // empty' /tmp/broadcast-result.json)
|
||||
BROADCAST_URL=$(jq -r '.notion_url // empty' /tmp/broadcast-result.json)
|
||||
echo "broadcast_title=$BROADCAST_TITLE" >> "$GITHUB_OUTPUT"
|
||||
echo "broadcast_url=$BROADCAST_URL" >> "$GITHUB_OUTPUT"
|
||||
echo "✅ 人格体处理完成,广播标题: $BROADCAST_TITLE"
|
||||
else
|
||||
echo "⚠️ /tmp/broadcast-result.json 未生成(人格体可能未产出广播)"
|
||||
echo "broadcast_title=" >> "$GITHUB_OUTPUT"
|
||||
echo "broadcast_url=" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
# ── Pipeline C:推送广播到飞书 ───────────────────────────
|
||||
pipeline-c-push:
|
||||
name: 📢 Pipeline C · 飞书广播推送
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pipeline-a-syslog, pipeline-b-persona]
|
||||
permissions: {}
|
||||
if: >-
|
||||
needs.pipeline-b-persona.outputs.broadcast_title != '' &&
|
||||
(needs.pipeline-a-syslog.outputs.chat_id != '' || needs.pipeline-a-syslog.outputs.sender_open_id != '')
|
||||
steps:
|
||||
- name: 📢 推送广播到飞书
|
||||
env:
|
||||
PUSH_URL: https://guanghulab.com/webhook/push-broadcast
|
||||
PUSH_TOKEN: ${{ secrets.PUSH_BROADCAST_TOKEN }}
|
||||
CHAT_ID: ${{ needs.pipeline-a-syslog.outputs.chat_id }}
|
||||
SENDER_OPEN_ID: ${{ needs.pipeline-a-syslog.outputs.sender_open_id }}
|
||||
BROADCAST_TITLE: ${{ needs.pipeline-b-persona.outputs.broadcast_title }}
|
||||
BROADCAST_URL: ${{ needs.pipeline-b-persona.outputs.broadcast_url }}
|
||||
run: |
|
||||
if [ -z "$PUSH_TOKEN" ]; then
|
||||
echo "⚠️ PUSH_BROADCAST_TOKEN 未配置,跳过飞书推送"
|
||||
exit 0
|
||||
fi
|
||||
echo "📢 推送广播到飞书..."
|
||||
echo " 标题: $BROADCAST_TITLE"
|
||||
echo " 目标: ${CHAT_ID:-$SENDER_OPEN_ID}"
|
||||
|
||||
HTTP_CODE=$(curl -s -o /tmp/push-response.txt -w "%{http_code}" \
|
||||
-X POST "$PUSH_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "x-push-token: $PUSH_TOKEN" \
|
||||
-d "$(jq -n \
|
||||
--arg chat_id "$CHAT_ID" \
|
||||
--arg sender_open_id "$SENDER_OPEN_ID" \
|
||||
--arg broadcast_title "$BROADCAST_TITLE" \
|
||||
--arg broadcast_content "人格体已验收,请查看完整广播。" \
|
||||
--arg broadcast_url "$BROADCAST_URL" \
|
||||
'{chat_id: $chat_id, sender_open_id: $sender_open_id, broadcast_title: $broadcast_title, broadcast_content: $broadcast_content, broadcast_url: $broadcast_url}')")
|
||||
|
||||
echo " HTTP 响应: $HTTP_CODE"
|
||||
cat /tmp/push-response.txt 2>/dev/null || true
|
||||
echo ""
|
||||
|
||||
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
||||
echo "✅ 广播已推送到飞书"
|
||||
else
|
||||
echo "❌ 推送失败 (HTTP $HTTP_CODE),可通过 push-broadcast-feishu workflow 手动补推"
|
||||
fi
|
||||
|
||||
# ── Pipeline D:Issues 巡检 ─────────────────────────────
|
||||
pipeline-d-issues:
|
||||
name: 🔍 Pipeline D · Issues 巡检
|
||||
|
|
|
|||
|
|
@ -885,6 +885,35 @@ async function main() {
|
|||
fs.appendFileSync(outputFile, 'result<<' + delimiter + '\n' + result + '\n' + delimiter + '\n');
|
||||
}
|
||||
|
||||
// 输出广播结果到 /tmp/broadcast-result.json(供飞书推送步骤使用)
|
||||
try {
|
||||
const broadcastResult = {
|
||||
title: '',
|
||||
summary: '',
|
||||
notion_url: '',
|
||||
dev_id: AUTHOR,
|
||||
raw_length: result.length,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// 尝试从人格体输出中提取广播标题(BC-xxx 格式)
|
||||
const bcMatch = result.match(/BC-[\w]+-\d+-[\w]+/);
|
||||
if (bcMatch) {
|
||||
broadcastResult.title = bcMatch[0];
|
||||
}
|
||||
|
||||
// 尝试提取摘要(取前100字符)
|
||||
const summaryLines = result.split('\n').filter(function (l) { return l.trim().length > 0; });
|
||||
if (summaryLines.length > 0) {
|
||||
broadcastResult.summary = summaryLines[0].slice(0, 100);
|
||||
}
|
||||
|
||||
fs.writeFileSync('/tmp/broadcast-result.json', JSON.stringify(broadcastResult, null, 2));
|
||||
console.log(' 📄 broadcast-result.json 已写入 /tmp/');
|
||||
} catch (e) {
|
||||
console.log(' ⚠️ broadcast-result.json 写入失败: ' + e.message);
|
||||
}
|
||||
|
||||
// 同时输出到 stdout 供调试
|
||||
console.log('');
|
||||
console.log('═══════════════════════════════════════════');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
// scripts/write-notion-syslog.js
|
||||
// 铸渊 · 飞书 SYSLOG → Notion 收件箱写入
|
||||
//
|
||||
// 读取 syslog-inbox/ 下的 JSON 文件,写入 Notion SYSLOG 收件箱数据库。
|
||||
// 用法: node scripts/write-notion-syslog.js <syslog-file-path>
|
||||
//
|
||||
// 环境变量:
|
||||
// NOTION_TOKEN Notion API token(必须)
|
||||
// NOTION_DB_SYSLOG SYSLOG 收件箱数据库 ID(必须)
|
||||
|
||||
'use strict';
|
||||
|
||||
const https = require('https');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 常量
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
const NOTION_VERSION = '2022-06-28';
|
||||
const NOTION_API_HOSTNAME = 'api.notion.com';
|
||||
const NOTION_RICH_TEXT_MAX = 2000;
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// HTTP 请求工具(复用 receive-syslog.js 模式)
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
function notionPost(endpoint, body, token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const payload = JSON.stringify(body);
|
||||
const opts = {
|
||||
hostname: NOTION_API_HOSTNAME,
|
||||
port: 443,
|
||||
path: endpoint,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + token,
|
||||
'Content-Type': 'application/json',
|
||||
'Notion-Version': NOTION_VERSION,
|
||||
'Content-Length': Buffer.byteLength(payload),
|
||||
},
|
||||
};
|
||||
const req = https.request(opts, res => {
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const parsed = JSON.parse(data);
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(parsed);
|
||||
} else {
|
||||
reject(new Error('Notion API ' + res.statusCode + ': ' + (parsed.message || data)));
|
||||
}
|
||||
} catch (e) {
|
||||
reject(new Error('Notion API parse error: ' + data));
|
||||
}
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.write(payload);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Notion 属性构建辅助
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
function richText(content) {
|
||||
const str = String(content || '');
|
||||
const chunks = [];
|
||||
for (let i = 0; i < str.length; i += NOTION_RICH_TEXT_MAX) {
|
||||
chunks.push({ type: 'text', text: { content: str.slice(i, i + NOTION_RICH_TEXT_MAX) } });
|
||||
}
|
||||
return chunks.length ? chunks : [{ type: 'text', text: { content: '' } }];
|
||||
}
|
||||
|
||||
function titleProp(text) {
|
||||
return { title: [{ type: 'text', text: { content: String(text || '').slice(0, 120) } }] };
|
||||
}
|
||||
|
||||
function richTextProp(text) {
|
||||
return { rich_text: richText(text) };
|
||||
}
|
||||
|
||||
function selectProp(name) {
|
||||
return { select: { name: String(name) } };
|
||||
}
|
||||
|
||||
function dateProp(dateStr) {
|
||||
return { date: { start: dateStr } };
|
||||
}
|
||||
|
||||
function checkboxProp(val) {
|
||||
return { checkbox: !!val };
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 主流程
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function main() {
|
||||
const filePath = process.argv[2];
|
||||
const notionToken = process.env.NOTION_TOKEN;
|
||||
const syslogDbId = process.env.NOTION_DB_SYSLOG;
|
||||
|
||||
if (!filePath) {
|
||||
console.error('❌ 用法: node write-notion-syslog.js <syslog-file-path>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!notionToken || !syslogDbId) {
|
||||
console.log('⚠️ 缺少 NOTION_TOKEN 或 NOTION_DB_SYSLOG,跳过 Notion 写入');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// 读取 SYSLOG 文件
|
||||
let entry;
|
||||
try {
|
||||
entry = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
} catch (e) {
|
||||
console.error('❌ 读取/解析文件失败: ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const filename = path.basename(filePath);
|
||||
const syslogText = entry.syslog_raw || entry.syslog || entry.content || '';
|
||||
const source = entry.source || 'unknown';
|
||||
const senderName = entry.sender_name || '';
|
||||
const senderOpenId = entry.sender_open_id || entry.sender_id || '';
|
||||
const chatId = entry.chat_id || '';
|
||||
const timestamp = entry.timestamp || new Date().toISOString();
|
||||
const dateStr = timestamp.split('T')[0] || new Date().toISOString().split('T')[0];
|
||||
|
||||
console.log('📋 写入 Notion SYSLOG 收件箱...');
|
||||
console.log(' 文件: ' + filename);
|
||||
console.log(' 来源: ' + source);
|
||||
console.log(' 发送者: ' + (senderName || senderOpenId || '未知'));
|
||||
|
||||
// 构建 Notion 页面属性
|
||||
const properties = {
|
||||
'标题': titleProp('飞书SYSLOG · ' + (senderName || source) + ' · ' + dateStr),
|
||||
'提交日期': dateProp(dateStr),
|
||||
'霜砚已读': checkboxProp(false),
|
||||
};
|
||||
|
||||
// 可选字段(如果 Notion 数据库有这些列)
|
||||
if (source) properties['来源'] = richTextProp(source);
|
||||
if (senderName) properties['发送者'] = richTextProp(senderName);
|
||||
if (senderOpenId) properties['发送者ID'] = richTextProp(senderOpenId);
|
||||
|
||||
// 构建页面内容
|
||||
const contentBlocks = [];
|
||||
|
||||
// SYSLOG 正文
|
||||
if (syslogText) {
|
||||
contentBlocks.push({
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
paragraph: {
|
||||
rich_text: richText(syslogText),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 原始 JSON(调试用)
|
||||
contentBlocks.push({
|
||||
object: 'block',
|
||||
type: 'code',
|
||||
code: {
|
||||
rich_text: richText(JSON.stringify(entry, null, 2)),
|
||||
language: 'json',
|
||||
},
|
||||
});
|
||||
|
||||
const body = {
|
||||
parent: { database_id: syslogDbId },
|
||||
properties,
|
||||
children: contentBlocks,
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await notionPost('/v1/pages', body, notionToken);
|
||||
console.log(' ✅ Notion SYSLOG 收件箱条目已创建: ' + result.id);
|
||||
} catch (err) {
|
||||
console.error(' ❌ Notion 写入失败: ' + err.message);
|
||||
// 不退出,允许后续步骤继续
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('❌ write-notion-syslog 失败: ' + err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in New Issue