@tapdb/tapdb-data-analysis 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -78,9 +78,7 @@ AI 会自动调用 `tapdb_query.py` 脚本查询数据并生成分析报告。
|
|
|
78
78
|
| 来源 | `source` | 新增设备/新增用户/转化率 |
|
|
79
79
|
| 玩家行为 | `player_behavior` | 游戏时长/启动次数 |
|
|
80
80
|
| 版本分布 | `version_distri` | 各版本活跃设备分布 |
|
|
81
|
-
| 运营概览 | `overview` | 收入/活跃/新增汇总 |
|
|
82
81
|
| 用户价值 | `user_value` | LTV (N日贡献) |
|
|
83
82
|
| 鲸鱼用户 | `whale_user` | 高付费用户排行 |
|
|
84
83
|
| 生命周期 | `life_cycle` | 付费转化率/金额/累计 |
|
|
85
84
|
| 广告变现 | `ad_monet` | 广告收入数据 |
|
|
86
|
-
|
package/package.json
CHANGED
|
@@ -3,26 +3,26 @@ name: tapdb-data-analysis
|
|
|
3
3
|
description: >
|
|
4
4
|
TapDB 游戏数据分析技能。用于查询和分析 TapDB 中的游戏运营数据,包括活跃(DAU/WAU/MAU)、
|
|
5
5
|
留存(1日留存-180日留存)、付费(收入/ARPU/ARPPU)、来源(新增/转化)、用户价值(LTV)、版本分布、
|
|
6
|
-
|
|
6
|
+
玩家行为、广告变现等指标。
|
|
7
7
|
当用户需要查询游戏数据、分析运营指标、对比项目表现、检测数据异常、生成数据报告时使用此技能。
|
|
8
8
|
触发关键词:TapDB、DAU、MAU、留存、付费、收入、ARPU、LTV、活跃、新增、来源、玩家行为、
|
|
9
|
-
|
|
9
|
+
版本分布、鲸鱼用户、广告变现、游戏数据分析。
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# TapDB 数据分析
|
|
13
13
|
|
|
14
|
-
> Skill 版本:v0.1.
|
|
14
|
+
> Skill 版本:v0.1.25
|
|
15
15
|
|
|
16
|
-
通过 Python 脚本调用 TapDB
|
|
16
|
+
通过 Python 脚本调用 TapDB 运营数据查询接口,获取游戏指标数据并分析。
|
|
17
17
|
|
|
18
18
|
## 环境要求
|
|
19
19
|
|
|
20
|
-
- 查询脚本: `<SKILL_DIR>/scripts/tapdb_query.py
|
|
21
|
-
- Python 3(优先用 `python3
|
|
20
|
+
- 查询脚本: `<SKILL_DIR>/scripts/tapdb_query.py`
|
|
21
|
+
- Python 3(优先用 `python3`;否则用 `python`)
|
|
22
22
|
- npm(用于 Skill 更新检查)
|
|
23
23
|
- 认证密钥 `TAPDB_MCP_KEY_CN` / `TAPDB_MCP_KEY_SG`
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## 运行前检查(每次讨论一个新话题或新一轮数据查询时使用)
|
|
26
26
|
|
|
27
27
|
### 1. Skill 更新
|
|
28
28
|
|
|
@@ -30,25 +30,13 @@ description: >
|
|
|
30
30
|
npm view @tapdb/tapdb-data-analysis version --registry https://registry.npmjs.org/
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
与本文件顶部 `Skill 版本`
|
|
33
|
+
与本文件顶部 `Skill 版本` 对比,不同则更新本 Skill
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
cd /tmp && \
|
|
37
|
-
npm pack @tapdb/tapdb-data-analysis@latest --registry https://registry.npmjs.org/ && \
|
|
38
|
-
tar -xzf tapdb-tapdb-data-analysis-*.tgz && \
|
|
39
|
-
cp -r package/tapdb-data-analysis/* <SKILL_DIR>/ && \
|
|
40
|
-
rm -rf package tapdb-tapdb-data-analysis-*.tgz
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
更新后**重新读取** `<SKILL_DIR>/SKILL.md`,以新版本为准。告知用户"TapDB 数据分析 Skill 已更新到 vX.X.X"。详情:https://www.npmjs.com/package/@tapdb/tapdb-data-analysis
|
|
35
|
+
更新后**重新读取** `<SKILL_DIR>/SKILL.md`,以新版本为准。告知用户"TapDB 数据分析 Skill 已更新到 vX.X.X",并给出更新内容。
|
|
44
36
|
|
|
45
37
|
### 2. 环境变量
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
[ -z "$TAPDB_MCP_KEY_CN" ] && echo "❌ CN 未设置" || echo "✅ CN 已配置"
|
|
49
|
-
[ -z "$TAPDB_MCP_KEY_SG" ] && echo "❌ SG 未设置" || echo "✅ SG 已配置"
|
|
50
|
-
```
|
|
51
|
-
|
|
39
|
+
检查 `TAPDB_MCP_KEY_CN` 和 `TAPDB_MCP_KEY_SG` 环境变量是否存在。
|
|
52
40
|
缺少则**停止操作**,引导配置:秘钥在 **TapDB 页面右上角 → 账号设置 → 秘钥管理**。国内 CN/海外 SG 各需独立秘钥。用户提供后按步骤 3 写入 shell 配置文件并验证。
|
|
53
41
|
|
|
54
42
|
### 3. 持久化检查
|
|
@@ -57,15 +45,14 @@ rm -rf package tapdb-tapdb-data-analysis-*.tgz
|
|
|
57
45
|
|
|
58
46
|
## 工作流程
|
|
59
47
|
|
|
60
|
-
1. **确认项目**: `list_projects` 获取项目列表(含 `id/name/appid/sticky/remark
|
|
48
|
+
1. **确认项目**: `list_projects` 获取项目列表(含 `id/name/appid/sticky/remark`,若返回列表过长则先保存到本地再查找,避免截断导致找不到需要的项目)
|
|
61
49
|
- 在 `name` 和 `remark` 中检索匹配,任一命中即为候选
|
|
62
50
|
- 多候选时优先 `sticky: true`;仍有多个则对每个做轻量探测(如 7 天 DAU):仅一个有数据→直接用;多个有数据→列出让用户选;全零→同样列出让用户选
|
|
63
51
|
2. **识别场景**: 按「场景路由」判断分析路径
|
|
64
52
|
3. **查看能力**: `describe <接口名>` 确认支持的指标/分组/过滤
|
|
65
53
|
4. **调用脚本**: 查询数据
|
|
66
|
-
5.
|
|
67
|
-
6.
|
|
68
|
-
7. **输出报告**: 按 `references/output_rules.md` 生成结论优先、可追溯的结构化报告
|
|
54
|
+
5. **分析**: 读 `references/metrics_glossary.md`(指标定义)、`references/analysis_guide.md`(方法论)
|
|
55
|
+
6. **输出报告**: 按 `references/output_rules.md` 生成结论优先、可追溯的结构化报告
|
|
69
56
|
|
|
70
57
|
## 场景路由
|
|
71
58
|
|
|
@@ -145,7 +132,6 @@ python3 <SKILL_DIR>/scripts/tapdb_query.py life_cycle -p 2588 -s 2026-02-01 -e 2
|
|
|
145
132
|
python3 <SKILL_DIR>/scripts/tapdb_query.py whale_user -p 2588 -s 2026-01-01 -e 2026-02-25
|
|
146
133
|
python3 <SKILL_DIR>/scripts/tapdb_query.py version_distri -p 2588 -s 2026-02-01 -e 2026-02-25
|
|
147
134
|
python3 <SKILL_DIR>/scripts/tapdb_query.py player_behavior -p 2588 -s 2026-02-01 -e 2026-02-25 -g time
|
|
148
|
-
python3 <SKILL_DIR>/scripts/tapdb_query.py overview -p 2588 --app-id abc123 -s 2026-02-01 -e 2026-02-25
|
|
149
135
|
python3 <SKILL_DIR>/scripts/tapdb_query.py raw /op/active '{"project_id":2588,"start_time":"2026-02-01 00:00:00.000","end_time":"2026-02-25 23:59:59.999","subject":"device","quota":"dau","group":{"col_name":"time","col_alias":"date","is_time":true,"trunc_unit":"day"},"is_de_water":false,"filters":[]}'
|
|
150
136
|
```
|
|
151
137
|
|
|
@@ -159,7 +145,6 @@ python3 <SKILL_DIR>/scripts/tapdb_query.py raw /op/active '{"project_id":2588,"s
|
|
|
159
145
|
| `source` | 来源/新增 | 通用参数 | `activation_time` |
|
|
160
146
|
| `player_behavior` | 玩家行为 | `--quota behavior\|duration` | `time` |
|
|
161
147
|
| `version_distri` | 版本分布 | 通用参数 | 按版本分组 |
|
|
162
|
-
| `overview` | 运营概览 | `--app-id`, `--interval`, `--quota income\|active\|activation` | 独立接口 |
|
|
163
148
|
| `user_value` | LTV | 通用参数 | `activation_time` |
|
|
164
149
|
| `whale_user` | 鲸鱼用户 | 通用参数 | 无分组 |
|
|
165
150
|
| `life_cycle` | 生命周期 | `--quota payment_amount\|payment_cvs_rate\|payment_cvs\|acc_payment` | `activation_time` |
|
|
@@ -171,13 +156,11 @@ python3 <SKILL_DIR>/scripts/tapdb_query.py raw /op/active '{"project_id":2588,"s
|
|
|
171
156
|
|
|
172
157
|
| 场景 | 阈值 | 方式 |
|
|
173
158
|
|------|------|------|
|
|
174
|
-
| 时间序列 | > 30 行 | 首
|
|
159
|
+
| 时间序列 | > 30 行 | 首15 + 尾15 |
|
|
175
160
|
| 分组维度 | > 20 行 | 前20 |
|
|
176
161
|
| 鲸鱼用户 | > 20 条 | 前20 |
|
|
177
|
-
| 留存列 DR1-DR180 | 自动 | 仅 DR1/3/7/14/30/60/90 |
|
|
178
|
-
| LTV 列 1-60_LTV | 自动 | 仅 LTV1/3/7/14/30/60/90 |
|
|
179
162
|
|
|
180
|
-
- 不加 `--all-retention` 通常仅返回 `DR1-DR30 + DR60/90/120/150/180`;加上后会额外补齐 `DR31-DR59`(及对应 `_newDevice/_rate`
|
|
163
|
+
- 不加 `--all-retention` 通常仅返回 `DR1-DR30 + DR60/90/120/150/180`;加上后会额外补齐 `DR31-DR59`(及对应 `_newDevice/_rate` 列)。
|
|
181
164
|
|
|
182
165
|
- 分析时利用 `_truncation.summary` 统计量,不要仅基于可见行下结论
|
|
183
166
|
- 多次查询:每次先提取关键数值再下一个查询,不累积原始数据
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
import argparse
|
|
13
13
|
import json
|
|
14
14
|
import os
|
|
15
|
-
import re
|
|
16
15
|
import sys
|
|
17
16
|
import urllib.request
|
|
18
17
|
import urllib.error
|
|
@@ -46,6 +45,13 @@ def get_config(region):
|
|
|
46
45
|
|
|
47
46
|
def http_request(method, url, headers, body=None):
|
|
48
47
|
try:
|
|
48
|
+
headers = dict(headers or {})
|
|
49
|
+
if not any(k.lower() == "user-agent" for k in headers):
|
|
50
|
+
headers["User-Agent"] = (
|
|
51
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
52
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
53
|
+
"Chrome/122.0.0.0 Safari/537.36"
|
|
54
|
+
)
|
|
49
55
|
data = json.dumps(body).encode("utf-8") if body else None
|
|
50
56
|
req = urllib.request.Request(url, data=data, headers=headers, method=method)
|
|
51
57
|
if data:
|
|
@@ -67,18 +73,14 @@ def output(data):
|
|
|
67
73
|
|
|
68
74
|
# ── 数据截断 ────────────────────────────────────────────────
|
|
69
75
|
|
|
70
|
-
_RE_DR = re.compile(r'^DR(\d+)')
|
|
71
|
-
_RE_N_LTV = re.compile(r'^(\d+)_LTV$')
|
|
72
|
-
_RETENTION_KEEP = {1, 3, 7, 14, 30, 60, 90}
|
|
73
|
-
_LTV_KEEP = {1, 3, 7, 14, 30, 60, 90}
|
|
74
76
|
_TIME_FIELDS = frozenset(("date", "time", "activation_time", "start_time",
|
|
75
77
|
"date_", "time_", "activation_time_", "start_time_"))
|
|
76
78
|
|
|
77
79
|
_MAX_TIME_ROWS = 30
|
|
78
80
|
_MAX_GROUP_ROWS = 20
|
|
79
81
|
_MAX_WHALE_ROWS = 20
|
|
80
|
-
_HEAD =
|
|
81
|
-
_TAIL =
|
|
82
|
+
_HEAD = 15
|
|
83
|
+
_TAIL = 15
|
|
82
84
|
|
|
83
85
|
|
|
84
86
|
def _numeric_summary(rows, limit=6):
|
|
@@ -95,33 +97,6 @@ def _numeric_summary(rows, limit=6):
|
|
|
95
97
|
return out
|
|
96
98
|
|
|
97
99
|
|
|
98
|
-
def _slim_columns(rows, cmd_type):
|
|
99
|
-
"""Drop intermediate DR/LTV columns, keep key day columns only."""
|
|
100
|
-
if not rows or not isinstance(rows[0], dict):
|
|
101
|
-
return rows, None
|
|
102
|
-
sample = rows[0]
|
|
103
|
-
if cmd_type == "retention":
|
|
104
|
-
regex, keep_set, label = _RE_DR, _RETENTION_KEEP, "DR"
|
|
105
|
-
elif cmd_type == "user_value":
|
|
106
|
-
regex, keep_set, label = _RE_N_LTV, _LTV_KEEP, "LTV"
|
|
107
|
-
else:
|
|
108
|
-
return rows, None
|
|
109
|
-
|
|
110
|
-
matched = {}
|
|
111
|
-
for k in sample:
|
|
112
|
-
m = regex.match(k)
|
|
113
|
-
if m:
|
|
114
|
-
matched[k] = int(m.group(1))
|
|
115
|
-
kept_count = sum(1 for d in matched.values() if d in keep_set)
|
|
116
|
-
if len(matched) <= kept_count + 2:
|
|
117
|
-
return rows, None
|
|
118
|
-
keep_keys = {k for k in sample if k not in matched or matched.get(k) in keep_set}
|
|
119
|
-
removed = len(matched) - kept_count
|
|
120
|
-
rows = [{k: v for k, v in r.items() if k in keep_keys} for r in rows]
|
|
121
|
-
days = "/".join(str(d) for d in sorted(keep_set))
|
|
122
|
-
return rows, f"kept {label}{days}, removed {removed} other {label} columns"
|
|
123
|
-
|
|
124
|
-
|
|
125
100
|
def _slim_rows(rows, cmd_type):
|
|
126
101
|
"""Truncate row count; time-series keeps head+tail, others keep head."""
|
|
127
102
|
if not rows:
|
|
@@ -211,9 +186,6 @@ def truncate_response(resp, cmd_type=None):
|
|
|
211
186
|
return resp
|
|
212
187
|
|
|
213
188
|
info = {}
|
|
214
|
-
rows, col_msg = _slim_columns(rows, cmd_type)
|
|
215
|
-
if col_msg:
|
|
216
|
-
info["columns"] = col_msg
|
|
217
189
|
rows, row_info = _slim_rows(rows, cmd_type)
|
|
218
190
|
if row_info:
|
|
219
191
|
info.update(row_info)
|
|
@@ -433,11 +405,6 @@ ENDPOINT_CAPS = {
|
|
|
433
405
|
"description": "版本分布: 各版本活跃/新增设备数(专用接口,忽略 group 参数,固定按版本分组)",
|
|
434
406
|
"returned_metrics": ["version", "allDevices", "newDevices", "upgradeDevices", "activeDevices", "NUDevices"],
|
|
435
407
|
},
|
|
436
|
-
"overview": {
|
|
437
|
-
"description": "运营概览: 收入/活跃/新增汇总(需 app_id,独立接口不走通用分组)",
|
|
438
|
-
"quotas": ["income", "active", "activation"],
|
|
439
|
-
"extra_params": ["app_id (必需)", "interval (minute|hour|day|week|month)"],
|
|
440
|
-
},
|
|
441
408
|
"user_value": {
|
|
442
409
|
"description": "用户价值(LTV): N日贡献",
|
|
443
410
|
"returned_metrics": ["activation", "N_LTV (1-60,90,120,150,180,210,240,270,300,330,360)"],
|
|
@@ -657,24 +624,6 @@ def cmd_player_behavior(args):
|
|
|
657
624
|
def cmd_version_distri(args):
|
|
658
625
|
do_query(args, "version_distri")
|
|
659
626
|
|
|
660
|
-
|
|
661
|
-
def cmd_overview(args):
|
|
662
|
-
key, base_url = get_config(args.region)
|
|
663
|
-
body = {
|
|
664
|
-
"project_id": int(args.project_id),
|
|
665
|
-
"app_id": args.app_id,
|
|
666
|
-
"start_date": args.start,
|
|
667
|
-
"end_date": args.end,
|
|
668
|
-
"interval": args.interval,
|
|
669
|
-
"quota": args.quota,
|
|
670
|
-
"use_cache": not getattr(args, "no_cache", False),
|
|
671
|
-
}
|
|
672
|
-
result = http_request("POST", f"{base_url}/mcp/op/op_overview", {"MCP-KEY": key}, body)
|
|
673
|
-
if not getattr(args, "no_truncate", False):
|
|
674
|
-
result = truncate_response(result, "overview")
|
|
675
|
-
output(result)
|
|
676
|
-
|
|
677
|
-
|
|
678
627
|
def cmd_user_value(args):
|
|
679
628
|
do_query(args, "user_value")
|
|
680
629
|
|
|
@@ -773,18 +722,6 @@ def main():
|
|
|
773
722
|
p = sub.add_parser("version_distri", help="版本分布: 各版本活跃设备数")
|
|
774
723
|
add_common_args(p)
|
|
775
724
|
|
|
776
|
-
# overview
|
|
777
|
-
p = sub.add_parser("overview", help="运营概览: 收入/活跃/新增汇总")
|
|
778
|
-
p.add_argument("-p", "--project-id", required=True, help="项目ID")
|
|
779
|
-
p.add_argument("--app-id", required=True, help="应用ID (从 list_projects 获取)")
|
|
780
|
-
p.add_argument("-s", "--start", required=True, help="开始日期")
|
|
781
|
-
p.add_argument("-e", "--end", required=True, help="结束日期")
|
|
782
|
-
p.add_argument("--interval", default="day", choices=["minute", "hour", "day", "week", "month"],
|
|
783
|
-
help="时间粒度 (默认 day)")
|
|
784
|
-
p.add_argument("--quota", default="income", choices=["income", "active", "activation"],
|
|
785
|
-
help="概览类型 (默认 income)")
|
|
786
|
-
p.add_argument("--no-cache", action="store_true")
|
|
787
|
-
|
|
788
725
|
# user_value (LTV)
|
|
789
726
|
p = sub.add_parser("user_value", help="用户价值(LTV): N日贡献")
|
|
790
727
|
add_common_args(p)
|
|
@@ -824,7 +761,6 @@ def main():
|
|
|
824
761
|
"source": cmd_source,
|
|
825
762
|
"player_behavior": cmd_player_behavior,
|
|
826
763
|
"version_distri": cmd_version_distri,
|
|
827
|
-
"overview": cmd_overview,
|
|
828
764
|
"user_value": cmd_user_value,
|
|
829
765
|
"whale_user": cmd_whale_user,
|
|
830
766
|
"life_cycle": cmd_life_cycle,
|