check-in-report-skill
Background
本 skill 配合 check-in-manager-skill 使用,负责统计分析和报告生成。
数据来源(v4 更新):
- 活动配置:
check-in-manager-skill/activities/{group_id}/{activity_id}.txt(自然语言规则描述) - 打卡记录:
check-in-manager-skill/records/{group_id}/{activity_id}/YYYY-MM-DD.json(结构化记录)
Activity ID 格式(v4 简化):{类型}_{创建者}_{时间戳}
- 示例:
running_ceceilyqi_1775702066、reading_bob_1775702401 - 纯英文/数字,无中文(详见 check-in-manager-skill 的 Activity ID v4 规范)
群组隔离:通过 group_id 实现目录级隔离,每个群的活动和记录完全独立
Workflow
Step 1 — 解析请求
确定:
- 时间周期:本日/本周/本月/自定义区间/历史累计
- 报告类型:进度排名(A)| 周期结算(B)| 跨周期对比(C)| 催办提醒(D)
- 目标活动:未指定时扫描当前群活动列表
模板说明见 references/report-templates.md。
Step 2 — 定位数据
获取群组 ID:
chat_id = inbound_metadata["chat_id"] # "wecom:T14370047A"
# 安全获取 group_id,不存在/为空则用处理后的 chat_id
group_id = inbound_metadata.get("group_id") or chat_id.replace(":", "_").replace("#", "_").replace("/", "_")
定位目录(相对路径):
CURRENT_SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILLS_DIR="$(dirname "$CURRENT_SKILL_DIR")"
MANAGER_DIR="${SKILLS_DIR}/check-in-manager-skill"
ACTIVITIES_DIR="${MANAGER_DIR}/activities/${GROUP_ID}"
RECORDS_DIR="${MANAGER_DIR}/records/${GROUP_ID}"
扫描活动:
ls ${ACTIVITIES_DIR}/*.txt # 仅当前群
读取规则:
cat ${ACTIVITIES_DIR}/{activity_id}.txt
提取:活动名、达标线、核心指标、排序方向、惩罚机制、特殊规则。
加载记录:
python3 scripts/load_records.py \
${RECORDS_DIR}/{activity_id} \
<start_date> <end_date>
Step 3 — 统计计算
基本调用:
python3 scripts/calc_stats.py '<records_json>' '<members_json>' \
--mode <mode> --metric <field> [--metric2 <field2>] [--factor <num>]
7种计算模式:
| 模式 | 使用场景 | 参数 | 示例 |
|------|---------|------|------|
| count | 打卡次数 | 无 | --mode count |
| sum | 累计值 | --metric distance | 总距离 |
| avg | 平均值 | --metric duration | 平均时长 |
| max / min | 最值 | --metric distance | 单次最远/最近 |
| divide_sum | 相除 | --metric duration --metric2 distance | 平均配速(时长÷距离) |
| multiply_sum | 乘系数 | --metric distance --factor 60 | 卡路里(距离×60) |
| last_minus_first | 差值 | --metric weight | 体重变化(末值-初值) |
输出格式(原始数值):
{
"老张": {
"count": 3,
"value": 3.95, // ⚠️ 原始数值,无单位
"records": [...]
}
}
关键点:
- ✅
value是纯数值(如3.95),不是格式化字符串(如3'57"/km) - ✅ 无打卡记录的成员自动返回
value: 0, count: 0 - ✅ 保留
records数组供二次分析
Step 4 — 格式化与报告生成
4.1 单位转换(AI 负责)
从活动规则 TXT 提取单位定义,将原始数值转换为可读文本:
| 指标 | 原始值 | 转换公式 | 结果 |
|------|--------|---------|------|
| 配速 | 3.95 | 分=⌊3.95⌋, 秒=(0.95×60) | 3'57"/km |
| 时长 | 85.0 | <60分钟显示分钟 | "85分钟" |
| 距离 | 21.5 | 保留1-2位小数 | "21.5公里" |
| 体重 | -2.5 | 带符号 | "-2.5kg" |
配速转换代码(核心):
minutes = int(pace_raw)
seconds = (pace_raw - minutes) * 60
result = f"{minutes}'{int(seconds)}\"/km"
4.2 生成报告
根据 Step 1 确定的报告类型,使用 references/report-templates.md 对应模板:
| 类型 | 场景 | 必含内容 |
|------|------|---------|
| A | 日常排名 | 周期、排名、核心指标 |
| B | 周期结算 | 达标/未达标名单、惩罚机制 |
| C | 跨周期对比 | delta、排名变化(需调用 compare_periods.py) |
| D | 催办提醒 | 落后成员名单、剩余时间 |
报告要求:
- ✅ 全员覆盖(未打卡成员也要列出)
- ✅ 格式化后的指标(不是原始数值)
- ✅ 结尾鼓励语
Step 5 — 回复用户
使用消息工具将报告推送给用户。
Constraints
- 数据真实性:仅使用
records/{group_id}/{activity_id}/中的实际记录 - 全员覆盖:未打卡成员也必须在报告中列出
- 规则驱动:达标线、排序方向、核心指标 100% 来自活动 TXT 文件
- 群组隔离:只统计当前群数据,不跨群访问
路径约定(v4)
相对路径发现:
CURRENT_SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MANAGER_DIR="$(dirname "$CURRENT_SKILL_DIR")/check-in-manager-skill"
目录结构:
skills/
├── check-in-manager-skill/
│ ├── activities/{group_id}/{activity_id}.txt
│ └── records/{group_id}/{activity_id}/YYYY-MM-DD.json
└── check-in-report-skill/
├── SKILL.md
└── scripts/
Activity ID 格式:{类型}_{创建者}_{时间戳}(纯英文/数字)
群组 ID 格式:wecom_T14370047A(从 chat_id 转换)
工具脚本
| 脚本 | 功能 |
|------|------|
| load_records.py | 加载日期范围内的记录 |
| calc_stats.py | 统计计算(7种模式) |
| compare_periods.py | 跨周期对比 |
| rank_and_qualify.py | 排名与达标判定 |
微信扫一扫