@puyinkai/xiaobao-cli 0.1.8 → 0.1.9

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.
Files changed (47) hide show
  1. package/dist/{api-client-zDBFgk0y.mjs → api-client-CDNjkArS.mjs} +1 -1
  2. package/dist/{api-CX99_4K7.mjs → api-fsHHWWa3.mjs} +1 -1
  3. package/dist/{audio-ShfvRomP.mjs → audio-CRSMqaKo.mjs} +2 -2
  4. package/dist/{auth-DpK81Vp5.mjs → auth-_3hBh87U.mjs} +1 -1
  5. package/dist/cli.mjs +10 -10
  6. package/dist/{consultant-CS9B42d3.mjs → consultant-E33hTGUO.mjs} +1 -1
  7. package/dist/{customer-B1cxRbJ9.mjs → customer-DcQ83oKD.mjs} +1 -1
  8. package/dist/{focus-DfNPPhm5.mjs → focus-XMRxnHPw.mjs} +1 -1
  9. package/dist/{list-DI1OD95x.mjs → list-B3nN4pd2.mjs} +1 -1
  10. package/dist/{list-CD08BRLk.mjs → list-CXquxzex.mjs} +1 -1
  11. package/dist/{list-CKlx8YuL.mjs → list-Cc4zcaNz.mjs} +1 -1
  12. package/dist/{list-DCcCS6LM.mjs → list-CnlQdzPp.mjs} +1 -1
  13. package/dist/{list-D56gEqiB.mjs → list-CrMOrnS-.mjs} +1 -1
  14. package/dist/{list-CnlFIFiY.mjs → list-DFdDcHFq.mjs} +1 -1
  15. package/dist/{list-Cu6WzPpA.mjs → list-dm9YaCG1.mjs} +1 -1
  16. package/dist/{project-BuQQewOs.mjs → project-BD0g4oAW.mjs} +1 -1
  17. package/dist/{qa-CKsKiQIm.mjs → qa-CdMcxCE_.mjs} +1 -1
  18. package/dist/{resistance-DsE-Ha6Y.mjs → resistance-6_V6At3T.mjs} +1 -1
  19. package/dist/{text-C3jhdPoe.mjs → text-C3Ap6L5n.mjs} +1 -1
  20. package/dist/{visit-CX0Mc1n6.mjs → visit-DoeECi8w.mjs} +1 -1
  21. package/dist/{whoami-CZVez-rm.mjs → whoami-z-76WaCP.mjs} +1 -1
  22. package/package.json +5 -1
  23. package/skills/wangxiaobao-audio-query/SKILL.md +2 -2
  24. package/skills/wangxiaobao-audio-wiki/SKILL.md +4 -4
  25. package/skills/wangxiaobao-customer-focus-query/SKILL.md +2 -2
  26. package/skills/wangxiaobao-customer-query/SKILL.md +2 -2
  27. package/skills/wangxiaobao-customer-resistance-query/SKILL.md +2 -2
  28. package/skills/wangxiaobao-html-to-pdf/SKILL.md +116 -0
  29. package/skills/wangxiaobao-html-to-pdf/scripts/html2pdf.py +132 -0
  30. package/skills/wangxiaobao-html-to-pdf/scripts/html2pdf_exact.py +92 -0
  31. package/skills/wangxiaobao-project-daily-report/SKILL.md +170 -0
  32. package/skills/wangxiaobao-project-daily-report/_meta.json +9 -0
  33. package/skills/wangxiaobao-project-daily-report/references/report_template.html +308 -0
  34. package/skills/wangxiaobao-project-daily-report/scripts/fetch_data.py +219 -0
  35. package/skills/wangxiaobao-project-daily-report/scripts/generate_report.py +1029 -0
  36. package/skills/wangxiaobao-project-daily-report/scripts/run.py +34 -0
  37. package/skills/wangxiaobao-project-weekly-report/SKILL.md +169 -0
  38. package/skills/wangxiaobao-project-weekly-report/scripts/generate_report.py +308 -0
  39. package/skills/wangxiaobao-project-weekly-report/scripts/html2pdf_fast.py +161 -0
  40. package/skills/wangxiaobao-project-weekly-report/scripts/logo_wangai.png +0 -0
  41. package/skills/wangxiaobao-project-weekly-report/scripts/logo_wangxiaobao.png +0 -0
  42. package/skills/wangxiaobao-project-weekly-report/scripts/prepare_data.py +682 -0
  43. package/skills/wangxiaobao-project-weekly-report/scripts/template.py +925 -0
  44. package/skills/wangxiaobao-quick-qa/SKILL.md +2 -2
  45. package/skills/wangxiaobao-shared/SKILL.md +5 -5
  46. package/skills/wangxiaobao-switch-project/SKILL.md +3 -3
  47. package/skills/wangxiaobao-visit-query/SKILL.md +2 -2
@@ -0,0 +1,219 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 旺小宝项目日报数据拉取脚本
4
+ 功能:拉取旺小宝API数据,生成日报所需数据
5
+ """
6
+ import json
7
+ import subprocess
8
+ import os
9
+ import argparse
10
+ from collections import Counter
11
+
12
+ # 项目配置(优先级:命令行参数 > 环境变量 > 默认值)
13
+ TENANT_ID = os.environ.get("XIAOBAO_TENANT_ID", "")
14
+ PROJECT_ID = os.environ.get("XIAOBAO_PROJECT_ID", "")
15
+ PROJECT_NAME = os.environ.get("XIAOBAO_PROJECT_NAME", "<项目名>")
16
+ # KPI指标(示例值 500 / 21000,请按项目实际目标调整)
17
+ MONTH_VISIT_TARGET = int(os.environ.get("XIAOBAO_MONTH_VISIT_TARGET", "500"))
18
+ MONTH_SALES_TARGET = int(os.environ.get("XIAOBAO_MONTH_SALES_TARGET", "21000"))
19
+ TOKEN_PATH = os.path.join(os.path.expanduser("~"), ".openclaw/state/wangxiaobao/token.json")
20
+
21
+
22
+ def get_token():
23
+ """获取旺小宝access token"""
24
+ with open(TOKEN_PATH, 'r') as f:
25
+ return json.load(f)['access_token']
26
+
27
+
28
+ def api_call(endpoint, body, token):
29
+ """调用旺小宝API"""
30
+ cmd = [
31
+ 'curl', '-s', '-X', 'POST',
32
+ f'https://open-ai.wangxiaobao.com{endpoint}',
33
+ '-H', f'Authorization: Bearer {token}',
34
+ '-H', f'X-Tenant-Id: {TENANT_ID}',
35
+ '-H', f'X-Project-Id: {PROJECT_ID}',
36
+ '-H', 'Content-Type: application/json',
37
+ '-d', body
38
+ ]
39
+ result = subprocess.run(cmd, capture_output=True, text=True)
40
+ return json.loads(result.stdout)
41
+
42
+
43
+ def get_yesterday_visits(token, yesterday):
44
+ """获取昨日来访数据"""
45
+ body = json.dumps({
46
+ "current": 1, "size": 100,
47
+ "startTime": f"{yesterday} 00:00:00",
48
+ "endTime": f"{yesterday} 23:59:59"
49
+ })
50
+ data = api_call("/ai-open/visits/page", body, token)
51
+ all_visits = data.get('data', {}).get('content', [])
52
+ # 过滤只保留昨日
53
+ return [v for v in all_visits if v.get('visitTime', '').startswith(yesterday)]
54
+
55
+
56
+ def get_month_visits(token, month_start, yesterday):
57
+ """获取本月来访数据"""
58
+ body = json.dumps({
59
+ "current": 1, "size": 500,
60
+ "startTime": f"{month_start} 00:00:00",
61
+ "endTime": f"{yesterday} 23:59:59"
62
+ })
63
+ data = api_call("/ai-open/visits/page", body, token)
64
+ all_visits = data.get('data', {}).get('content', [])
65
+ # 过滤本月
66
+ return [v for v in all_visits if v.get('visitTime', '').startswith('2026-05-')]
67
+
68
+
69
+ def get_customers(token, month_start, yesterday):
70
+ """获取客户画像数据"""
71
+ body = json.dumps({
72
+ "page": 1, "size": 500,
73
+ "startTime": f"{month_start} 00:00:00",
74
+ "endTime": f"{yesterday} 23:59:59"
75
+ })
76
+ data = api_call("/ai-open/customers/page", body, token)
77
+ return data.get('data', {}).get('content', [])
78
+
79
+
80
+ def get_stock_customers(token, three_months_ago, yesterday):
81
+ """获取存量客户(近3月未成交)"""
82
+ body = json.dumps({
83
+ "page": 1, "size": 100,
84
+ "startTime": f"{three_months_ago} 00:00:00",
85
+ "endTime": f"{yesterday} 23:59:59"
86
+ })
87
+ data = api_call("/ai-open/customers/page", body, token)
88
+ all_custs = data.get('data', {}).get('content', [])
89
+ # 过滤未成交
90
+ return [c for c in all_custs if c.get('dealStatus') != 1]
91
+
92
+
93
+ def analyze_intent(customers):
94
+ """分析意向等级分布"""
95
+ intent_dist = Counter()
96
+ for c in customers:
97
+ level = c.get('intentLevel', '未知') or '未知'
98
+ if level == '':
99
+ level = '未知'
100
+ intent_dist[level] += 1
101
+ return dict(intent_dist)
102
+
103
+
104
+ def analyze_channel(customers):
105
+ """分析渠道分布"""
106
+ channel_dist = Counter()
107
+ for c in customers:
108
+ tags = c.get('dynamicTags', {})
109
+ channel = tags.get('五大类来访渠道', '未知')
110
+ if channel == '':
111
+ channel = '未知'
112
+ channel_dist[channel] += 1
113
+ return dict(channel_dist)
114
+
115
+
116
+ def main(date_str='2026-05-21'):
117
+ """主函数"""
118
+ today = date_str
119
+ yesterday = '2026-05-20'
120
+ month_start = '2026-05-01'
121
+ three_months_ago = '2026-02-20'
122
+
123
+ print("="*60)
124
+ print(f"{PROJECT_NAME}日报数据拉取 - {today}")
125
+ print("="*60)
126
+
127
+ token = get_token()
128
+
129
+ # 1. 昨日来访
130
+ print("\n[1] 拉取昨日来访数据...")
131
+ yesterday_visits = get_yesterday_visits(token, yesterday)
132
+ print(f" 昨日来访: {len(yesterday_visits)}组")
133
+
134
+ # 2. 本月来访
135
+ print("\n[2] 拉取本月来访数据...")
136
+ month_visits = get_month_visits(token, month_start, yesterday)
137
+ print(f" 本月来访: {len(month_visits)}组")
138
+
139
+ # 3. 客户画像
140
+ print("\n[3] 拉取客户画像数据...")
141
+ customers = get_customers(token, month_start, yesterday)
142
+ print(f" 本月客户总数: {len(customers)}")
143
+
144
+ # 意向等级
145
+ intent_dist = analyze_intent(customers)
146
+ print("\n 意向等级分布:")
147
+ for level, cnt in sorted(intent_dist.items(), key=lambda x: -x[1]):
148
+ print(f" {level}: {cnt}组")
149
+
150
+ # 渠道分布
151
+ channel_dist = analyze_channel(customers)
152
+ print("\n 渠道分布:")
153
+ for ch, cnt in sorted(channel_dist.items(), key=lambda x: -x[1])[:5]:
154
+ print(f" {ch}: {cnt}组")
155
+
156
+ # 4. 存量客户
157
+ print("\n[4] 拉取存量客户数据...")
158
+ stock_customers = get_stock_customers(token, three_months_ago, yesterday)
159
+ print(f" 存量客户(未成交): {len(stock_customers)}组")
160
+
161
+ # 5. 成交客户
162
+ print("\n[5] 分析成交数据...")
163
+ deal_customers = [c for c in customers if c.get('dealStatus') == 1]
164
+ deal_intent = analyze_intent(deal_customers)
165
+ print(f" 本月成交: {len(deal_customers)}组")
166
+ print(" 成交意向等级:", deal_intent)
167
+
168
+ # 保存数据
169
+ report_data = {
170
+ 'date': today,
171
+ 'yesterday': yesterday,
172
+ 'project_name': PROJECT_NAME,
173
+ 'month_visit_target': MONTH_VISIT_TARGET,
174
+ 'month_visit_actual': len(month_visits),
175
+ 'yesterday_visits': len(yesterday_visits),
176
+ 'yesterday_visit_list': [{
177
+ 'time': v['visitTime'].split(' ')[1],
178
+ 'advisor': v['userName'],
179
+ 'count': v['visitCount'],
180
+ 'duration': int(int(v.get('visitTimer', '0')) / 60000) if v.get('visitTimer', '0') != '0' else 0
181
+ } for v in yesterday_visits],
182
+ 'month_sales_target': MONTH_SALES_TARGET,
183
+ 'month_deals': len(deal_customers),
184
+ 'visit_intent': intent_dist,
185
+ 'channel_dist': channel_dist,
186
+ 'stock_total': len(stock_customers),
187
+ 'deal_intent': deal_intent
188
+ }
189
+
190
+ output_path = os.path.join(os.getcwd(), "final_report_data.json")
191
+ with open(output_path, 'w', encoding='utf-8') as f:
192
+ json.dump(report_data, f, ensure_ascii=False, indent=2)
193
+
194
+ print(f"\n数据已保存: {output_path}")
195
+ return report_data
196
+
197
+
198
+ if __name__ == "__main__":
199
+ parser = argparse.ArgumentParser(description="旺小宝项目日报数据拉取")
200
+ parser.add_argument("date", nargs="?", default="2026-05-21", help="日期 YYYY-MM-DD")
201
+ parser.add_argument("--tenant-id", help="旺小宝租户ID(覆盖环境变量)")
202
+ parser.add_argument("--project-id", help="旺小宝项目ID(覆盖环境变量)")
203
+ parser.add_argument("--project-name", help="项目名称(覆盖环境变量)")
204
+ parser.add_argument("--month-visit-target", type=int, help="月度来访目标")
205
+ parser.add_argument("--month-sales-target", type=int, help="月度销售目标(万元)")
206
+ args = parser.parse_args()
207
+
208
+ if args.tenant_id:
209
+ TENANT_ID = args.tenant_id
210
+ if args.project_id:
211
+ PROJECT_ID = args.project_id
212
+ if args.project_name:
213
+ PROJECT_NAME = args.project_name
214
+ if args.month_visit_target is not None:
215
+ MONTH_VISIT_TARGET = args.month_visit_target
216
+ if args.month_sales_target is not None:
217
+ MONTH_SALES_TARGET = args.month_sales_target
218
+
219
+ main(args.date)