@pn-data/pn-data-analysis 0.0.1 → 0.0.3
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 +21 -3
- package/package.json +2 -2
- package/pn-data-analysis/SKILL.md +62 -11
- package/pn-data-analysis/pn_query.py +74 -7
package/README.md
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PN中台 AI数据分析
|
|
2
2
|
|
|
3
3
|
Cursor Agent Skill — 通过 pn_mid_v2 中台 API 查询项目的**流水、活跃、留存、来源**数据。
|
|
4
4
|
|
|
5
|
+
## 环境变量配置
|
|
6
|
+
|
|
7
|
+
使用前需配置认证密钥。
|
|
8
|
+
|
|
9
|
+
密钥在**中台右上角 -> 生成数据分析密钥**中可以获取。
|
|
10
|
+
|
|
11
|
+
### 必需变量
|
|
12
|
+
|
|
13
|
+
密钥必须写入 shell 配置文件(zsh 用户写 `~/.zshrc`,bash 用户写 `~/.bashrc`),以确保所有终端会话和 AI 工具都能读取到:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export PN_DATA_ANALYSIS_TOKEN="your-token-here" # 数据分析密钥
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
将上面内容写入对应的 shell 配置文件后执行 `source` 使其生效。
|
|
20
|
+
|
|
21
|
+
> **注意**:仅在当前终端 `export` 而不写入配置文件的话,新终端窗口或 AI Agent 启动的 shell 会话将无法读取到密钥。Skill 在每次会话首次使用时会自动检查配置文件中是否存在密钥,如果缺失会自动写入。
|
|
22
|
+
|
|
5
23
|
## 安装
|
|
6
24
|
|
|
7
25
|
```bash
|
|
8
26
|
# 作为项目 Cursor Skill
|
|
9
|
-
npm install @pn/pn-data-analysis
|
|
10
|
-
# 将 node_modules/@pn/pn-data-analysis/pn-data-analysis/ 复制或链接到 .cursor/skills/
|
|
27
|
+
npm install @pn-data/pn-data-analysis
|
|
28
|
+
# 将 node_modules/@pn-data/pn-data-analysis/pn-data-analysis/ 复制或链接到 .cursor/skills/
|
|
11
29
|
```
|
|
12
30
|
|
|
13
31
|
## 使用方式
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pn-data/pn-data-analysis",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Cursor Agent Skill for querying pn_mid_v2 project data
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Cursor Agent Skill for querying pn_mid_v2 project data",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cursor",
|
|
7
7
|
"cursor-skill",
|
|
@@ -3,6 +3,18 @@ name: pn-data-analysis
|
|
|
3
3
|
description: Analyzes project data on the middle platform (pn_mid_v2). Use when querying 收入, 流水, 商店流水, 活跃, 留存, 来源, project revenue, activity, retention, or source data by project and month.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
> Skill 版本:v0.0.3
|
|
7
|
+
|
|
8
|
+
# Skill 更新
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm view @pn-data/pn-data-analysis version --registry https://registry.npmjs.org/
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
与本文件顶部 `Skill 版本` 对比,不同则更新本 Skill
|
|
15
|
+
|
|
16
|
+
更新后**重新读取** `<SKILL_DIR>/SKILL.md`,以新版本为准。告知用户"中台数据分析 Skill 已更新到 vX.X.X"。
|
|
17
|
+
|
|
6
18
|
# 中台项目数据分析
|
|
7
19
|
|
|
8
20
|
通过 `pn_query.py` 远程查询 pn_mid_v2 中台各项目数据,支持**流水、活跃、留存、来源**四类查询。
|
|
@@ -13,19 +25,55 @@ description: Analyzes project data on the middle platform (pn_mid_v2). Use when
|
|
|
13
25
|
- **关键词**:用pn、用中台
|
|
14
26
|
- **数据类型词**:收入、流水、商店流水、活跃、留存、来源
|
|
15
27
|
|
|
16
|
-
##
|
|
28
|
+
## 执行顺序:先取 listProject 学习 id 与名称
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
**在跑任何按项目查询(pay/activity/retention/source)之前**,先取一次项目列表,建立「项目 id ↔ 名称」对应关系:
|
|
31
|
+
|
|
32
|
+
1. **先执行**:`python3 <SKILL_DIR>/pn_query.py projects`(或 `--json` 取原始列表)
|
|
33
|
+
2. **从返回中学习**:每条为 `id | name | tag`,记下 id、name、tag 的对应关系
|
|
34
|
+
3. **再解析用户请求**:用户提到「项目名」「项目X」「tag」或数字 id 时,用该列表解析出**真实的项目 id (pid)**,再调用 `pn_query.py <pid> <dataType> <YYYY-MM>`
|
|
35
|
+
|
|
36
|
+
未先取 listProject 时,不要猜测 pid;名称/别称与 id 的对应关系以当次 listProject 结果为准。
|
|
37
|
+
|
|
38
|
+
## 项目名称解析(依赖上面 listProject 结果)
|
|
39
|
+
|
|
40
|
+
- 用户说**数字 id**(如 2023、2088)→ 直接作为 pid
|
|
41
|
+
- 用户说**项目名称或 tag** → 用已获取的项目列表按 name/tag 匹配,取对应 id 作为 pid
|
|
42
|
+
- 仅当列表中存在明确对应时再发起数据查询;无法匹配时提示用户说明项目 id 或名称
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 执行前:检查 PN_DATA_ANALYSIS_TOKEN
|
|
47
|
+
|
|
48
|
+
**每次执行查询前**必须确保环境变量 `PN_DATA_ANALYSIS_TOKEN` 已存在:
|
|
49
|
+
|
|
50
|
+
1. **先检查**:`printenv PN_DATA_ANALYSIS_TOKEN` 或 `echo $PN_DATA_ANALYSIS_TOKEN`
|
|
51
|
+
2. **若为空或未设置**:先执行 `source` 加载用户 shell 配置
|
|
52
|
+
3. **再执行**下面的查询命令
|
|
53
|
+
|
|
54
|
+
密钥需用户在中台右上角 -> 生成数据分析密钥 获取并写入 `~/.zshrc` 或 `~/.bashrc`:`export PN_DATA_ANALYSIS_TOKEN="..."`
|
|
20
55
|
|
|
21
56
|
---
|
|
22
57
|
|
|
23
58
|
## 查询命令
|
|
24
59
|
|
|
25
|
-
|
|
60
|
+
脚本位置:`<SKILL_DIR>/pn_query.py`
|
|
61
|
+
|
|
62
|
+
### 获取项目列表(id、name、tag)
|
|
63
|
+
|
|
64
|
+
无需 pid/月份,直接获取当前密钥对应用户可访问的项目列表,用于学习 **id、name、tag** 的对应关系:
|
|
26
65
|
|
|
27
66
|
```bash
|
|
28
|
-
python3
|
|
67
|
+
python3 <SKILL_DIR>/pn_query.py projects
|
|
68
|
+
python3 <SKILL_DIR>/pn_query.py projects --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
输出格式:`id | name | tag`,每行一个项目。
|
|
72
|
+
|
|
73
|
+
### 按项目与月份查询数据
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python3 <SKILL_DIR>/pn_query.py <pid> <dataType> <YYYY-MM> [选项]
|
|
29
77
|
```
|
|
30
78
|
|
|
31
79
|
### 四类数据
|
|
@@ -59,23 +107,26 @@ python3 .cursor/skills/pn-data-analysis/pn_query.py <pid> <dataType> <YYYY-MM> [
|
|
|
59
107
|
## 示例
|
|
60
108
|
|
|
61
109
|
```bash
|
|
110
|
+
# 获取项目列表
|
|
111
|
+
python3 <SKILL_DIR>/pn_query.py projects
|
|
112
|
+
|
|
62
113
|
# 流水
|
|
63
|
-
python3
|
|
114
|
+
python3 <SKILL_DIR>/pn_query.py 2023 pay 2026-01
|
|
64
115
|
|
|
65
116
|
# 活跃(全平台)
|
|
66
|
-
python3
|
|
117
|
+
python3 <SKILL_DIR>/pn_query.py 2023 activity 2026-01
|
|
67
118
|
|
|
68
119
|
# 留存(全平台)
|
|
69
|
-
python3
|
|
120
|
+
python3 <SKILL_DIR>/pn_query.py 2023 retention 2026-01
|
|
70
121
|
|
|
71
122
|
# 来源
|
|
72
|
-
python3
|
|
123
|
+
python3 <SKILL_DIR>/pn_query.py 2023 source 2026-01
|
|
73
124
|
|
|
74
125
|
# 仅 iOS 活跃
|
|
75
|
-
python3
|
|
126
|
+
python3 <SKILL_DIR>/pn_query.py 2023 activity 2026-01 --appPlatform=1
|
|
76
127
|
|
|
77
128
|
# 原始 JSON
|
|
78
|
-
python3
|
|
129
|
+
python3 <SKILL_DIR>/pn_query.py 2023 retention 2026-01 --json
|
|
79
130
|
```
|
|
80
131
|
|
|
81
132
|
## 默认行为
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
"""
|
|
3
3
|
pn_query.py - 远程查询 pn_mid_v2 中台数据
|
|
4
4
|
|
|
5
|
-
通过 HTTP API 调用 pnDataAnalysis
|
|
5
|
+
通过 HTTP API 调用 pnDataAnalysis 接口,查询项目的流水、活跃、留存、来源数据,或获取项目列表。
|
|
6
6
|
|
|
7
7
|
用法:
|
|
8
|
+
python3 pn_query.py projects # 获取项目列表
|
|
8
9
|
python3 pn_query.py <pid> <dataType> <YYYY-MM> [选项]
|
|
9
10
|
python3 pn_query.py 2023 pay 2026-01
|
|
10
11
|
python3 pn_query.py 2023 activity 2026-01
|
|
@@ -14,20 +15,66 @@ pn_query.py - 远程查询 pn_mid_v2 中台数据
|
|
|
14
15
|
选项:
|
|
15
16
|
--appPlatform=N 0=全平台(默认) 1=iOS 2=Android
|
|
16
17
|
--group=N 分组类型,默认2(日期)。留存默认8(账号)
|
|
18
|
+
--json 输出原始 JSON
|
|
17
19
|
"""
|
|
18
20
|
|
|
19
21
|
import argparse
|
|
20
22
|
import json
|
|
23
|
+
import os
|
|
21
24
|
import sys
|
|
22
25
|
import urllib.request
|
|
23
26
|
from calendar import monthrange
|
|
24
27
|
from datetime import datetime
|
|
25
28
|
|
|
26
|
-
API_BASE = "https://pnv2.17995api.net"
|
|
29
|
+
# API_BASE = "https://pnv2.17995api.net"
|
|
30
|
+
API_BASE = "http://localhost:811" # 本地测试
|
|
27
31
|
API_PATH = "/service/pn_data_analysis"
|
|
32
|
+
ENV_TOKEN = "PN_DATA_ANALYSIS_TOKEN"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def list_projects() -> list:
|
|
36
|
+
"""获取当前用户可访问的项目列表。"""
|
|
37
|
+
token = os.environ.get(ENV_TOKEN)
|
|
38
|
+
if not token:
|
|
39
|
+
raise SystemExit(
|
|
40
|
+
f"未配置 {ENV_TOKEN}。请在中台右上角 -> 生成数据分析密钥 获取后写入 shell 配置(如 ~/.zshrc)并 source 生效。"
|
|
41
|
+
)
|
|
42
|
+
url = f"{API_BASE}{API_PATH}"
|
|
43
|
+
payload = {"dataType": "listProject"}
|
|
44
|
+
headers = {
|
|
45
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
46
|
+
"X-Pn-Token": token,
|
|
47
|
+
}
|
|
48
|
+
req = urllib.request.Request(
|
|
49
|
+
url,
|
|
50
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
51
|
+
headers=headers,
|
|
52
|
+
method="POST",
|
|
53
|
+
)
|
|
54
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
55
|
+
out = json.loads(resp.read().decode("utf-8"))
|
|
56
|
+
return out if isinstance(out, list) else out.get("list", out)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def format_projects(data: list) -> str:
|
|
60
|
+
if not data:
|
|
61
|
+
return "无项目数据"
|
|
62
|
+
lines = ["项目列表 (id | name | tag):"]
|
|
63
|
+
for p in data:
|
|
64
|
+
pid = p.get("id", "")
|
|
65
|
+
name = p.get("name", "")
|
|
66
|
+
tag = p.get("tag", "")
|
|
67
|
+
lines.append(f" {pid} | {name} | {tag}")
|
|
68
|
+
return "\n".join(lines)
|
|
28
69
|
|
|
29
70
|
|
|
30
71
|
def query(pid: int, data_type: str, month: str, app_platform: int = 0, group: int = 2) -> dict:
|
|
72
|
+
token = os.environ.get(ENV_TOKEN)
|
|
73
|
+
if not token:
|
|
74
|
+
raise SystemExit(
|
|
75
|
+
f"未配置 {ENV_TOKEN}。请在中台右上角 -> 生成数据分析密钥 获取后写入 shell 配置(如 ~/.zshrc)并 source 生效。"
|
|
76
|
+
)
|
|
77
|
+
|
|
31
78
|
st_date = datetime.strptime(f"{month}-01", "%Y-%m-%d")
|
|
32
79
|
y, m = st_date.year, st_date.month
|
|
33
80
|
_, last = monthrange(y, m)
|
|
@@ -43,7 +90,10 @@ def query(pid: int, data_type: str, month: str, app_platform: int = 0, group: in
|
|
|
43
90
|
"useCache": True,
|
|
44
91
|
}
|
|
45
92
|
url = f"{API_BASE}{API_PATH}"
|
|
46
|
-
headers = {
|
|
93
|
+
headers = {
|
|
94
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
95
|
+
"X-Pn-Token": token,
|
|
96
|
+
}
|
|
47
97
|
req = urllib.request.Request(
|
|
48
98
|
url,
|
|
49
99
|
data=json.dumps(payload).encode("utf-8"),
|
|
@@ -114,19 +164,36 @@ def format_source(data: list) -> str:
|
|
|
114
164
|
|
|
115
165
|
def main():
|
|
116
166
|
parser = argparse.ArgumentParser(description="pn_mid_v2 远程数据查询")
|
|
117
|
-
parser.add_argument("pid",
|
|
118
|
-
parser.add_argument("dataType", choices=["pay", "activity", "retention", "source"], help="数据类型")
|
|
119
|
-
parser.add_argument("month", help="月份 YYYY-MM")
|
|
167
|
+
parser.add_argument("pid", nargs="?", help="项目 ID,或写 projects 获取项目列表")
|
|
168
|
+
parser.add_argument("dataType", nargs="?", choices=["pay", "activity", "retention", "source"], help="数据类型")
|
|
169
|
+
parser.add_argument("month", nargs="?", help="月份 YYYY-MM")
|
|
120
170
|
parser.add_argument("--appPlatform", type=int, default=0, help="0=全平台 1=iOS 2=Android (默认0)")
|
|
121
171
|
parser.add_argument("--group", type=int, default=None, help="分组类型,默认2(日期),留存默认8(账号)")
|
|
122
172
|
parser.add_argument("--json", action="store_true", help="输出原始 JSON")
|
|
123
173
|
args = parser.parse_args()
|
|
124
174
|
|
|
175
|
+
# 获取项目列表
|
|
176
|
+
if (args.pid or "").lower() in ("projects", "listproject", "list"):
|
|
177
|
+
try:
|
|
178
|
+
result = list_projects()
|
|
179
|
+
except Exception as e:
|
|
180
|
+
print(f"查询失败: {e}", file=sys.stderr)
|
|
181
|
+
sys.exit(1)
|
|
182
|
+
if args.json:
|
|
183
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
184
|
+
else:
|
|
185
|
+
print(format_projects(result))
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
if args.pid is None or args.dataType is None or args.month is None:
|
|
189
|
+
parser.error("查询数据时需指定 pid dataType month,或使用 pid=projects 获取项目列表")
|
|
190
|
+
|
|
191
|
+
pid = int(args.pid)
|
|
125
192
|
if args.group is None:
|
|
126
193
|
args.group = 8 if args.dataType == "retention" else 2
|
|
127
194
|
|
|
128
195
|
try:
|
|
129
|
-
result = query(
|
|
196
|
+
result = query(pid, args.dataType, args.month, args.appPlatform, args.group)
|
|
130
197
|
except Exception as e:
|
|
131
198
|
print(f"查询失败: {e}", file=sys.stderr)
|
|
132
199
|
sys.exit(1)
|