@rine-kit/pubg-intelligence 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/dist/src/analytics.d.ts +176 -0
- package/dist/src/analytics.js +431 -0
- package/dist/src/analytics.js.map +1 -0
- package/dist/src/assistant.d.ts +87 -0
- package/dist/src/assistant.js +310 -0
- package/dist/src/assistant.js.map +1 -0
- package/dist/src/battle.d.ts +280 -0
- package/dist/src/battle.js +1249 -0
- package/dist/src/battle.js.map +1 -0
- package/dist/src/combat-long.d.ts +42 -0
- package/dist/src/combat-long.js +146 -0
- package/dist/src/combat-long.js.map +1 -0
- package/dist/src/combat-quality.d.ts +101 -0
- package/dist/src/combat-quality.js +253 -0
- package/dist/src/combat-quality.js.map +1 -0
- package/dist/src/evaluation-fixtures.d.ts +13 -0
- package/dist/src/evaluation-fixtures.js +144 -0
- package/dist/src/evaluation-fixtures.js.map +1 -0
- package/dist/src/evaluation-replay.d.ts +5 -0
- package/dist/src/evaluation-replay.js +107 -0
- package/dist/src/evaluation-replay.js.map +1 -0
- package/dist/src/evaluation.d.ts +140 -0
- package/dist/src/evaluation.js +180 -0
- package/dist/src/evaluation.js.map +1 -0
- package/dist/src/experiment-store.d.ts +56 -0
- package/dist/src/experiment-store.js +159 -0
- package/dist/src/experiment-store.js.map +1 -0
- package/dist/src/field.d.ts +103 -0
- package/dist/src/field.js +298 -0
- package/dist/src/field.js.map +1 -0
- package/dist/src/fights.d.ts +89 -0
- package/dist/src/fights.js +238 -0
- package/dist/src/fights.js.map +1 -0
- package/dist/src/highlights.d.ts +44 -0
- package/dist/src/highlights.js +153 -0
- package/dist/src/highlights.js.map +1 -0
- package/dist/src/index.d.ts +24 -0
- package/dist/src/index.js +25 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/insights.d.ts +44 -0
- package/dist/src/insights.js +343 -0
- package/dist/src/insights.js.map +1 -0
- package/dist/src/intent.d.ts +40 -0
- package/dist/src/intent.js +119 -0
- package/dist/src/intent.js.map +1 -0
- package/dist/src/landing.d.ts +74 -0
- package/dist/src/landing.js +195 -0
- package/dist/src/landing.js.map +1 -0
- package/dist/src/lobby.d.ts +48 -0
- package/dist/src/lobby.js +209 -0
- package/dist/src/lobby.js.map +1 -0
- package/dist/src/match-insight.d.ts +165 -0
- package/dist/src/match-insight.js +542 -0
- package/dist/src/match-insight.js.map +1 -0
- package/dist/src/match-relative.d.ts +73 -0
- package/dist/src/match-relative.js +145 -0
- package/dist/src/match-relative.js.map +1 -0
- package/dist/src/match-story.d.ts +155 -0
- package/dist/src/match-story.js +636 -0
- package/dist/src/match-story.js.map +1 -0
- package/dist/src/profiles.d.ts +41 -0
- package/dist/src/profiles.js +136 -0
- package/dist/src/profiles.js.map +1 -0
- package/dist/src/raw-telemetry-archive.d.ts +29 -0
- package/dist/src/raw-telemetry-archive.js +340 -0
- package/dist/src/raw-telemetry-archive.js.map +1 -0
- package/dist/src/raw-telemetry-backfill.d.ts +28 -0
- package/dist/src/raw-telemetry-backfill.js +144 -0
- package/dist/src/raw-telemetry-backfill.js.map +1 -0
- package/dist/src/research.d.ts +89 -0
- package/dist/src/research.js +376 -0
- package/dist/src/research.js.map +1 -0
- package/dist/src/rhythm.d.ts +104 -0
- package/dist/src/rhythm.js +260 -0
- package/dist/src/rhythm.js.map +1 -0
- package/dist/src/streaks.d.ts +117 -0
- package/dist/src/streaks.js +367 -0
- package/dist/src/streaks.js.map +1 -0
- package/dist/src/style.d.ts +304 -0
- package/dist/src/style.js +1461 -0
- package/dist/src/style.js.map +1 -0
- package/dist/src/tactics.d.ts +88 -0
- package/dist/src/tactics.js +1221 -0
- package/dist/src/tactics.js.map +1 -0
- package/package.json +49 -3
- package/README.md +0 -3
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { newcombeDifference, wilsonInterval, median, } from './analytics.js';
|
|
2
|
+
import { DISTANCE_GAP_POINTS, ZONE_MIN_SAMPLES, } from './field.js';
|
|
3
|
+
import { FIGHT_MIN_GROUP } from './fights.js';
|
|
4
|
+
export const INSIGHT_RULE_VERSION = 'highlight-rules-v1';
|
|
5
|
+
export const INSIGHT_MAX = 6;
|
|
6
|
+
export const INSIGHT_MAP_MIN_MATCHES = 15;
|
|
7
|
+
export const INSIGHT_REVIVE_MIN_KNOCKS = 15;
|
|
8
|
+
export const INSIGHT_DEATH_MIN = 30;
|
|
9
|
+
export const INSIGHT_RECENT_MATCHES = 20;
|
|
10
|
+
const pct = (value, digits = 0) => value === null ? '—' : `${(value * 100).toFixed(digits)}%`;
|
|
11
|
+
const interval = (rate) => rate.low === null || rate.high === null
|
|
12
|
+
? '区间不足'
|
|
13
|
+
: `95% 区间 ${pct(rate.low)}–${pct(rate.high)}`;
|
|
14
|
+
/** Orders warnings first, then good news, then context, and keeps the list short enough to read. */
|
|
15
|
+
export function rankInsights(insights, max = INSIGHT_MAX) {
|
|
16
|
+
const weight = { warn: 0, good: 1, info: 2 };
|
|
17
|
+
return insights
|
|
18
|
+
.sort((left, right) => weight[left.tone] - weight[right.tone] || left.id.localeCompare(right.id))
|
|
19
|
+
.slice(0, max);
|
|
20
|
+
}
|
|
21
|
+
export function buildPerformanceInsights(input) {
|
|
22
|
+
const insights = [];
|
|
23
|
+
for (const member of input.lineups.members) {
|
|
24
|
+
if (member.withMatches < 5 ||
|
|
25
|
+
member.withoutMatches < 5 ||
|
|
26
|
+
!member.difference.significant ||
|
|
27
|
+
member.difference.delta === null)
|
|
28
|
+
continue;
|
|
29
|
+
const delta = member.difference.delta;
|
|
30
|
+
insights.push({
|
|
31
|
+
id: `member-${member.id}`,
|
|
32
|
+
tone: delta > 0 ? 'good' : 'warn',
|
|
33
|
+
title: `${member.name} ${delta > 0 ? '在场时前十率明显更高' : '在场时前十率明显更低'}`,
|
|
34
|
+
detail: `在场 ${pct(member.withTop10.rate)}(${member.withMatches} 场)对比缺席 ${pct(member.withoutTop10.rate)}(${member.withoutMatches} 场),差 ${delta >= 0 ? '+' : ''}${(delta * 100).toFixed(0)} 个百分点。这是相关性,不等于个人贡献。`,
|
|
35
|
+
evidence: `差值 95% 区间 ${(member.difference.low * 100).toFixed(0)} 到 ${(member.difference.high * 100).toFixed(0)}pt`,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const rankedMaps = input.maps.filter((map) => map.rankedMatches >= INSIGHT_MAP_MIN_MATCHES);
|
|
39
|
+
const totalTrials = input.maps.reduce((sum, map) => sum + map.top10.trials, 0);
|
|
40
|
+
const totalSuccess = input.maps.reduce((sum, map) => sum + map.top10.successes, 0);
|
|
41
|
+
for (const map of rankedMaps) {
|
|
42
|
+
const rest = wilsonInterval(totalSuccess - map.top10.successes, totalTrials - map.top10.trials);
|
|
43
|
+
const difference = newcombeDifference(map.top10, rest);
|
|
44
|
+
if (!difference.significant || difference.delta === null)
|
|
45
|
+
continue;
|
|
46
|
+
insights.push({
|
|
47
|
+
id: `map-${map.mapName}`,
|
|
48
|
+
tone: difference.delta > 0 ? 'good' : 'warn',
|
|
49
|
+
title: `${map.label}前十率${difference.delta > 0 ? '明显高于' : '明显低于'}其他地图`,
|
|
50
|
+
detail: `${map.label} ${pct(map.top10.rate)}(${map.rankedMatches} 场)对比其他地图 ${pct(rest.rate)},中位名次 ${map.medianPlacement === null ? '未知' : `#${map.medianPlacement}`}。`,
|
|
51
|
+
evidence: `差值 95% 区间 ${(difference.low * 100).toFixed(0)} 到 ${(difference.high * 100).toFixed(0)}pt`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
for (const player of input.squad.players) {
|
|
55
|
+
const damage = player.metrics.find((metric) => metric.key === 'damage');
|
|
56
|
+
if (!damage ||
|
|
57
|
+
damage.form === 'steady' ||
|
|
58
|
+
damage.form === 'insufficient' ||
|
|
59
|
+
damage.formZ === null)
|
|
60
|
+
continue;
|
|
61
|
+
insights.push({
|
|
62
|
+
id: `form-${player.id}`,
|
|
63
|
+
tone: damage.form === 'hot' ? 'good' : 'warn',
|
|
64
|
+
title: `${player.name} 近 5 场伤害${damage.form === 'hot' ? '明显高于' : '明显低于'}自己的常态`,
|
|
65
|
+
detail: `此前基线中位 ${Math.round(damage.baselineMedian ?? 0)},近 5 场均值 ${Math.round(damage.recentMean ?? 0)}。`,
|
|
66
|
+
evidence: `稳健 z = ${damage.formZ.toFixed(1)}(|z| ≥ 1.5 才标记)`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const recent = input.series.slice(-INSIGHT_RECENT_MATCHES);
|
|
70
|
+
const before = input.series.slice(0, -INSIGHT_RECENT_MATCHES);
|
|
71
|
+
const rate = (items) => {
|
|
72
|
+
const ranked = items.filter((point) => point.placement !== null);
|
|
73
|
+
return wilsonInterval(ranked.filter((point) => point.placement <= 10).length, ranked.length);
|
|
74
|
+
};
|
|
75
|
+
if (recent.length >= INSIGHT_RECENT_MATCHES && before.length >= 30) {
|
|
76
|
+
const recentRate = rate(recent);
|
|
77
|
+
const beforeRate = rate(before);
|
|
78
|
+
const difference = newcombeDifference(recentRate, beforeRate);
|
|
79
|
+
if (difference.significant && difference.delta !== null) {
|
|
80
|
+
insights.push({
|
|
81
|
+
id: 'recent-top10',
|
|
82
|
+
tone: difference.delta > 0 ? 'good' : 'warn',
|
|
83
|
+
title: `近 ${INSIGHT_RECENT_MATCHES} 场前十率${difference.delta > 0 ? '明显回升' : '明显下滑'}`,
|
|
84
|
+
detail: `近 ${INSIGHT_RECENT_MATCHES} 场 ${pct(recentRate.rate)} 对比此前 ${pct(beforeRate.rate)}。`,
|
|
85
|
+
evidence: `差值 95% 区间 ${(difference.low * 100).toFixed(0)} 到 ${(difference.high * 100).toFixed(0)}pt`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const recentDamage = median(recent.map((point) => point.damage));
|
|
89
|
+
const beforeDamage = median(before.map((point) => point.damage));
|
|
90
|
+
if (recentDamage !== null &&
|
|
91
|
+
beforeDamage !== null &&
|
|
92
|
+
beforeDamage > 0 &&
|
|
93
|
+
Math.abs(recentDamage / beforeDamage - 1) >= 0.3) {
|
|
94
|
+
const change = recentDamage / beforeDamage - 1;
|
|
95
|
+
insights.push({
|
|
96
|
+
id: 'recent-damage',
|
|
97
|
+
tone: change > 0 ? 'good' : 'warn',
|
|
98
|
+
title: `近 ${INSIGHT_RECENT_MATCHES} 场人均伤害中位数${change > 0 ? '上升' : '下降'} ${Math.abs(change * 100).toFixed(0)}%`,
|
|
99
|
+
detail: `中位数 ${Math.round(recentDamage)} 对比此前 ${Math.round(beforeDamage)}(用中位数,避免个别爆发场次拉偏)。`,
|
|
100
|
+
evidence: `${recent.length} 场对 ${before.length} 场;变化 ≥ 30% 才提示`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return rankInsights(insights);
|
|
105
|
+
}
|
|
106
|
+
export function buildCombatInsights(input) {
|
|
107
|
+
const { combat, deaths, landing } = input;
|
|
108
|
+
const insights = [];
|
|
109
|
+
const revive = combat.revive;
|
|
110
|
+
if (revive.knocked >= INSIGHT_REVIVE_MIN_KNOCKS &&
|
|
111
|
+
revive.reviveRate.high !== null &&
|
|
112
|
+
revive.reviveRate.high < 0.4) {
|
|
113
|
+
const finish = combat.finish.finishRate.rate;
|
|
114
|
+
insights.push({
|
|
115
|
+
id: 'revive-weak',
|
|
116
|
+
tone: 'warn',
|
|
117
|
+
title: `队员倒地后只有 ${pct(revive.reviveRate.rate)} 被救起`,
|
|
118
|
+
detail: `${revive.knocked} 次倒地中救起 ${revive.revived} 次、被补掉 ${revive.killed} 次${finish === null ? '' : `;对比我们补掉对手的 ${pct(finish)},救援是明显短板`}。`,
|
|
119
|
+
evidence: `${interval(revive.reviveRate)},样本 ${revive.knocked} 次`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (deaths.deaths >= INSIGHT_DEATH_MIN &&
|
|
123
|
+
deaths.afterKnock.rate.low !== null &&
|
|
124
|
+
deaths.afterKnock.rate.low > 0.5) {
|
|
125
|
+
insights.push({
|
|
126
|
+
id: 'death-after-knock',
|
|
127
|
+
tone: 'warn',
|
|
128
|
+
title: `${pct(deaths.afterKnock.rate.rate)} 的淘汰发生在倒地之后`,
|
|
129
|
+
detail: `${deaths.deaths} 次淘汰里有 ${deaths.afterKnock.count} 次是先倒地再被补掉。倒地后的封烟、拉人或爬走有机会改变结果。`,
|
|
130
|
+
evidence: interval(deaths.afterKnock.rate),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const first = combat.firstKnock;
|
|
134
|
+
if (first.forUs + first.againstUs >= 20 &&
|
|
135
|
+
first.ourRate.low !== null &&
|
|
136
|
+
first.ourRate.high !== null) {
|
|
137
|
+
if (first.ourRate.low > 0.5) {
|
|
138
|
+
insights.push({
|
|
139
|
+
id: 'first-knock',
|
|
140
|
+
tone: 'good',
|
|
141
|
+
title: `首倒占比 ${pct(first.ourRate.rate)},开战更常是我方先手`,
|
|
142
|
+
detail: `${first.forUs + first.againstUs} 次有明确首倒的交战里我方先倒地对手 ${first.forUs} 次。`,
|
|
143
|
+
evidence: interval(first.ourRate),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else if (first.ourRate.high < 0.5) {
|
|
147
|
+
insights.push({
|
|
148
|
+
id: 'first-knock',
|
|
149
|
+
tone: 'warn',
|
|
150
|
+
title: `首倒占比只有 ${pct(first.ourRate.rate)},开战更常被对手先手`,
|
|
151
|
+
detail: `${first.forUs + first.againstUs} 次有明确首倒的交战里对手先倒地我方 ${first.againstUs} 次。`,
|
|
152
|
+
evidence: interval(first.ourRate),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const lead = combat.leadConversion;
|
|
157
|
+
if (lead.held + lead.lost >= 20 && lead.heldRate.rate !== null && lead.heldRate.rate < 0.8) {
|
|
158
|
+
insights.push({
|
|
159
|
+
id: 'lead-lost',
|
|
160
|
+
tone: 'info',
|
|
161
|
+
title: `先手优势有 ${pct(1 - lead.heldRate.rate)} 被追平或反超`,
|
|
162
|
+
detail: `我方首倒后,${lead.lost} 次被对手把倒地数追平或反超(共 ${lead.held + lead.lost} 次)。`,
|
|
163
|
+
evidence: interval(lead.heldRate),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (combat.groups >= 30 &&
|
|
167
|
+
combat.thirdParty.againstRate.rate !== null &&
|
|
168
|
+
combat.thirdParty.againstRate.rate >= 0.3) {
|
|
169
|
+
insights.push({
|
|
170
|
+
id: 'third-party',
|
|
171
|
+
tone: 'info',
|
|
172
|
+
title: `${pct(combat.thirdParty.againstRate.rate)} 的交战出现第三方介入候选`,
|
|
173
|
+
detail: `${combat.groups} 次交战里有 ${combat.thirdParty.againstUs} 次时间重叠的第三队接触;这只是候选,不代表对方意图。`,
|
|
174
|
+
evidence: interval(combat.thirdParty.againstRate),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const topStage = [...deaths.stages].sort((left, right) => right.deaths - left.deaths)[0];
|
|
178
|
+
if (deaths.deaths >= INSIGHT_DEATH_MIN &&
|
|
179
|
+
topStage &&
|
|
180
|
+
topStage.stage !== '未知' &&
|
|
181
|
+
topStage.share >= 0.5) {
|
|
182
|
+
insights.push({
|
|
183
|
+
id: 'death-stage',
|
|
184
|
+
tone: 'info',
|
|
185
|
+
title: `${pct(topStage.share)} 的淘汰集中在${topStage.stage}`,
|
|
186
|
+
detail: `${deaths.deaths} 次淘汰里 ${topStage.deaths} 次发生在${topStage.stage}阶段(按淘汰时剩余队伍数划分)。`,
|
|
187
|
+
evidence: `样本 ${deaths.deaths} 次`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const map = landing.maps.find((item) => item.matchesWithLanding >= 6);
|
|
191
|
+
if (map && map.topCellRepeatRate !== null && map.topCellRepeatRate >= 0.5) {
|
|
192
|
+
insights.push({
|
|
193
|
+
id: `landing-${map.mapName}`,
|
|
194
|
+
tone: 'info',
|
|
195
|
+
title: `${map.label}落点集中:${pct(map.topCellRepeatRate)} 的场次落在 ${map.cells[0].cell} 格`,
|
|
196
|
+
detail: `${map.matchesWithLanding} 场有落点记录,队内成员落点距小队中心中位 ${map.medianSpreadMeters === null ? '未知' : `${Math.round(map.medianSpreadMeters)}m`}。`,
|
|
197
|
+
evidence: `样本 ${map.matchesWithLanding} 场`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return rankInsights(insights);
|
|
201
|
+
}
|
|
202
|
+
export const FIELD_INSIGHT_MAX = 10;
|
|
203
|
+
const points = (value) => `${value >= 0 ? '+' : ''}${(value * 100).toFixed(0)}pt`;
|
|
204
|
+
export function buildFieldInsights(input) {
|
|
205
|
+
const { fights, distance, zone, landing, roles } = input;
|
|
206
|
+
const insights = [];
|
|
207
|
+
const decided = (bucket) => bucket.wins + bucket.losses;
|
|
208
|
+
const initiative = fights.initiatorEdge;
|
|
209
|
+
if (initiative.significant && initiative.delta !== null) {
|
|
210
|
+
const us = fights.byInitiator[0];
|
|
211
|
+
const them = fights.byInitiator[1];
|
|
212
|
+
insights.push({
|
|
213
|
+
id: 'fight-initiator',
|
|
214
|
+
tone: initiative.delta > 0 ? 'good' : 'warn',
|
|
215
|
+
title: initiative.delta > 0
|
|
216
|
+
? `先手开火的交战胜率明显更高:${pct(us.winRate.rate)} 对 ${pct(them.winRate.rate)}`
|
|
217
|
+
: `先手开火反而更吃亏:${pct(us.winRate.rate)} 对 ${pct(them.winRate.rate)}`,
|
|
218
|
+
detail: `我方先手 ${decided(us)} 场分出胜负,对方先手 ${decided(them)} 场;先手 = 交战中第一次有效伤害的发起方。`,
|
|
219
|
+
evidence: `差 ${points(initiative.delta)},区间 ${(initiative.low * 100).toFixed(0)} 到 ${(initiative.high * 100).toFixed(0)}pt`,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
const third = fights.thirdPartyEdge;
|
|
223
|
+
if (third.significant && third.delta !== null) {
|
|
224
|
+
const withThird = fights.byThirdParty[0];
|
|
225
|
+
const duel = fights.byThirdParty[1];
|
|
226
|
+
insights.push({
|
|
227
|
+
id: 'fight-third-party',
|
|
228
|
+
tone: third.delta > 0 ? 'good' : 'warn',
|
|
229
|
+
title: third.delta < 0
|
|
230
|
+
? `有第三方介入时胜率降到 ${pct(withThird.winRate.rate)}(两队对战 ${pct(duel.winRate.rate)})`
|
|
231
|
+
: `有第三方介入时胜率反而更高 ${pct(withThird.winRate.rate)}`,
|
|
232
|
+
detail: `${decided(withThird)} 场有第三方候选、${decided(duel)} 场两队对战。第三方只是时间重叠的候选。`,
|
|
233
|
+
evidence: `差 ${points(third.delta)},区间 ${(third.low * 100).toFixed(0)} 到 ${(third.high * 100).toFixed(0)}pt`,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
for (const stage of fights.byStage) {
|
|
237
|
+
if (decided(stage) < FIGHT_MIN_GROUP || stage.key === '未知')
|
|
238
|
+
continue;
|
|
239
|
+
const restWins = fights.overall.wins - stage.wins;
|
|
240
|
+
const restLosses = fights.overall.losses - stage.losses;
|
|
241
|
+
if (restWins + restLosses < FIGHT_MIN_GROUP)
|
|
242
|
+
continue;
|
|
243
|
+
const difference = newcombeDifference(stage.winRate, wilsonInterval(restWins, restWins + restLosses));
|
|
244
|
+
if (!difference.significant || difference.delta === null)
|
|
245
|
+
continue;
|
|
246
|
+
insights.push({
|
|
247
|
+
id: `fight-stage-${stage.key}`,
|
|
248
|
+
tone: difference.delta > 0 ? 'good' : 'warn',
|
|
249
|
+
title: `${stage.label}阶段的交战胜率${difference.delta > 0 ? '明显偏高' : '明显偏低'}:${pct(stage.winRate.rate)}`,
|
|
250
|
+
detail: `该阶段 ${decided(stage)} 场分出胜负,其余阶段合计 ${pct(wilsonInterval(restWins, restWins + restLosses).rate)}。`,
|
|
251
|
+
evidence: `差 ${points(difference.delta)},区间 ${(difference.low * 100).toFixed(0)} 到 ${(difference.high * 100).toFixed(0)}pt`,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (distance.longRangeGap !== null && Math.abs(distance.longRangeGap) >= DISTANCE_GAP_POINTS) {
|
|
255
|
+
const dealt = distance.bands.slice(2).reduce((sum, band) => sum + (band.dealtShare ?? 0), 0);
|
|
256
|
+
const taken = distance.bands.slice(2).reduce((sum, band) => sum + (band.takenShare ?? 0), 0);
|
|
257
|
+
insights.push({
|
|
258
|
+
id: 'distance-gap',
|
|
259
|
+
tone: distance.longRangeGap > 0 ? 'warn' : 'good',
|
|
260
|
+
title: distance.longRangeGap > 0
|
|
261
|
+
? `承受的远距离伤害(≥75m)占 ${pct(taken)},而我们打出的只占 ${pct(dealt)}`
|
|
262
|
+
: `我们的远距离输出(≥75m)占 ${pct(dealt)},高于承受的 ${pct(taken)}`,
|
|
263
|
+
detail: distance.longRangeGap > 0
|
|
264
|
+
? '对手更常在远处消耗我们,这说明我们的交战距离偏近或缺少远程火力/掩体。'
|
|
265
|
+
: '我们更常占据远距离优势,近距离被动挨打的比例较低。',
|
|
266
|
+
evidence: `按枪械伤害统计,打出 ${Math.round(distance.totalDealt)}、承受 ${Math.round(distance.totalTaken)};差值需 ≥ ${DISTANCE_GAP_POINTS * 100}pt`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const outside = [...zone.phases]
|
|
270
|
+
.filter((phase) => phase.samples >= ZONE_MIN_SAMPLES &&
|
|
271
|
+
phase.outsideRate.low !== null &&
|
|
272
|
+
phase.outsideRate.low > 0.15)
|
|
273
|
+
.sort((left, right) => (right.outsideRate.rate ?? 0) - (left.outsideRate.rate ?? 0))[0];
|
|
274
|
+
if (outside) {
|
|
275
|
+
insights.push({
|
|
276
|
+
id: `zone-outside-${outside.phase}`,
|
|
277
|
+
tone: 'warn',
|
|
278
|
+
title: `第 ${outside.phase} 圈有 ${pct(outside.outsideRate.rate)} 的时间在毒圈里`,
|
|
279
|
+
detail: `该圈共 ${outside.samples} 个位置样本,毒圈伤害合计 ${Math.round(outside.blueDamage)}。转圈偏晚会白白损血并被迫在不利位置交战。`,
|
|
280
|
+
evidence: interval(outside.outsideRate),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
const lateEdge = zone.phases.filter((phase) => phase.phase >= 6 &&
|
|
284
|
+
phase.samples >= ZONE_MIN_SAMPLES &&
|
|
285
|
+
phase.binShares &&
|
|
286
|
+
phase.binShares[2] + phase.binShares[3] >= 0.6)[0];
|
|
287
|
+
if (lateEdge?.binShares) {
|
|
288
|
+
insights.push({
|
|
289
|
+
id: 'zone-late-edge',
|
|
290
|
+
tone: 'info',
|
|
291
|
+
title: `第 ${lateEdge.phase} 圈有 ${pct(lateEdge.binShares[2] + lateEdge.binShares[3])} 的时间贴着圈边或在圈外`,
|
|
292
|
+
detail: '决赛圈靠边更容易被两面夹击、也更容易被压缩空间;靠近圈中心通常有更多回旋余地。',
|
|
293
|
+
evidence: `样本 ${lateEdge.samples} 个位置点;圈边 = 距安全区中心 ≥ 85% 半径`,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
if (zone.blueDamageShare !== null && zone.blueDamageShare >= 0.15 && zone.matches >= 20) {
|
|
297
|
+
insights.push({
|
|
298
|
+
id: 'zone-blue-damage',
|
|
299
|
+
tone: 'info',
|
|
300
|
+
title: `毒圈伤害占全部承伤的 ${pct(zone.blueDamageShare)}`,
|
|
301
|
+
detail: `${zone.matches} 场平均每场吃毒 ${Math.round(zone.blueDamagePerMatch ?? 0)} 点;这部分伤害本可以通过更早转圈或用载具避免。`,
|
|
302
|
+
evidence: `样本 ${zone.matches} 场`,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (landing.contest.earlyWipeEdge.significant && (landing.contest.earlyWipeEdge.delta ?? 0) > 0) {
|
|
306
|
+
const [calm, , crowded] = landing.contest.buckets;
|
|
307
|
+
const top10 = landing.contest.top10Edge;
|
|
308
|
+
insights.push({
|
|
309
|
+
id: 'landing-contest',
|
|
310
|
+
tone: 'warn',
|
|
311
|
+
title: `落点附近有队伍争抢时,早崩率高出 ${points(landing.contest.earlyWipeEdge.delta)}`,
|
|
312
|
+
detail: `无争抢 ${calm.matches} 场早崩 ${pct(calm.earlyWipe.rate)};有争抢的场次更高${crowded.matches ? `(2 队及以上 ${crowded.matches} 场 ${pct(crowded.earlyWipe.rate)})` : ''}。但前十率${top10.delta === null ? '样本不足' : top10.significant ? `也有差异(${points(top10.delta)})` : `差异不显著(${points(top10.delta)})`}:争抢带来的主要是开局的翻车风险,不一定拉低最终名次。早崩 = 全队最长生存不足 7 分钟,争抢 = 500m 内有其他队降落。`,
|
|
313
|
+
evidence: `早崩差区间 ${(landing.contest.earlyWipeEdge.low * 100).toFixed(0)} 到 ${(landing.contest.earlyWipeEdge.high * 100).toFixed(0)}pt,共 ${landing.contest.matches} 场`,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
for (const player of roles) {
|
|
317
|
+
for (const title of player.titles) {
|
|
318
|
+
const share = title === '开团手'
|
|
319
|
+
? player.firstKnockShare
|
|
320
|
+
: title.startsWith('先锋盾')
|
|
321
|
+
? player.firstDownedShare
|
|
322
|
+
: title === '救援担当'
|
|
323
|
+
? player.reviveShare
|
|
324
|
+
: player.killShare;
|
|
325
|
+
insights.push({
|
|
326
|
+
id: `role-${player.accountId}-${title}`,
|
|
327
|
+
tone: 'info',
|
|
328
|
+
title: `${player.name}:${title}(占 ${pct(share)})`,
|
|
329
|
+
detail: title === '开团手'
|
|
330
|
+
? '交战里第一个打倒对手的人最常是他。'
|
|
331
|
+
: title.startsWith('先锋盾')
|
|
332
|
+
? '交战里第一个被打倒的人最常是他,说明他经常顶在最前面或被集火。'
|
|
333
|
+
: title === '救援担当'
|
|
334
|
+
? '队内最多的救援来自他。'
|
|
335
|
+
: '队内最多的人头由他收割。',
|
|
336
|
+
evidence: `${player.fights} 次参与交战;占比 ≥ ${ROLE_TITLE_SHARE_TEXT} 才授予称号`,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return rankInsights(insights, FIELD_INSIGHT_MAX);
|
|
341
|
+
}
|
|
342
|
+
const ROLE_TITLE_SHARE_TEXT = '40%';
|
|
343
|
+
//# sourceMappingURL=insights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/insights.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type LanguageModel } from 'ai';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const ResearchIntentSchema: z.ZodObject<{
|
|
4
|
+
action: z.ZodEnum<{
|
|
5
|
+
trend: "trend";
|
|
6
|
+
summary: "summary";
|
|
7
|
+
player_comparison: "player_comparison";
|
|
8
|
+
map_breakdown: "map_breakdown";
|
|
9
|
+
telemetry_coverage: "telemetry_coverage";
|
|
10
|
+
unsupported: "unsupported";
|
|
11
|
+
}>;
|
|
12
|
+
metric: z.ZodNullable<z.ZodEnum<{
|
|
13
|
+
damage: "damage";
|
|
14
|
+
kills: "kills";
|
|
15
|
+
matches: "matches";
|
|
16
|
+
wins: "wins";
|
|
17
|
+
top10: "top10";
|
|
18
|
+
revives: "revives";
|
|
19
|
+
survival_time: "survival_time";
|
|
20
|
+
knocks: "knocks";
|
|
21
|
+
}>>;
|
|
22
|
+
groupBy: z.ZodNullable<z.ZodEnum<{
|
|
23
|
+
map: "map";
|
|
24
|
+
player: "player";
|
|
25
|
+
week: "week";
|
|
26
|
+
}>>;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
export type ResearchIntent = z.infer<typeof ResearchIntentSchema>;
|
|
29
|
+
export type ResearchPlanSource = 'ai-sdk' | 'local-rule';
|
|
30
|
+
export interface ResearchPlan {
|
|
31
|
+
intent: ResearchIntent;
|
|
32
|
+
source: ResearchPlanSource;
|
|
33
|
+
}
|
|
34
|
+
export declare function redactSensitiveText(value: string): string;
|
|
35
|
+
export declare class NaturalLanguageResearchPlanner {
|
|
36
|
+
private readonly model?;
|
|
37
|
+
constructor(model?: Exclude<LanguageModel, string> | undefined);
|
|
38
|
+
plan(message: string): Promise<ResearchPlan>;
|
|
39
|
+
}
|
|
40
|
+
export declare function classifyResearchQuestion(message: string): ResearchIntent;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { generateText, tool } from 'ai';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const ResearchIntentSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
action: z.enum([
|
|
6
|
+
'summary',
|
|
7
|
+
'trend',
|
|
8
|
+
'player_comparison',
|
|
9
|
+
'map_breakdown',
|
|
10
|
+
'telemetry_coverage',
|
|
11
|
+
'unsupported',
|
|
12
|
+
]),
|
|
13
|
+
metric: z
|
|
14
|
+
.enum(['damage', 'kills', 'knocks', 'revives', 'wins', 'top10', 'matches', 'survival_time'])
|
|
15
|
+
.nullable(),
|
|
16
|
+
groupBy: z.enum(['week', 'map', 'player']).nullable(),
|
|
17
|
+
})
|
|
18
|
+
.strict();
|
|
19
|
+
const DEFAULT_INTENT = { action: 'summary', metric: 'damage', groupBy: null };
|
|
20
|
+
export function redactSensitiveText(value) {
|
|
21
|
+
return value
|
|
22
|
+
.slice(0, 1200)
|
|
23
|
+
.replace(/(?<!\d)1[3-9]\d{9}(?!\d)/gu, '[手机号已隐藏]')
|
|
24
|
+
.replace(/(?:~\/|\/(?:Users|private|tmp|DATA|Volumes|var|home|workspace|mnt)\/)[^\s"'<>]+/giu, '[路径已隐藏]')
|
|
25
|
+
.replace(/\b(?:sk-[A-Za-z0-9]{20,}|gh[pousr]_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|Bearer\s+[A-Za-z0-9._-]{20,})\b/giu, '[凭据已隐藏]')
|
|
26
|
+
.replace(/\b(api[_ -]?key|access[_ -]?token|app[_ -]?secret|bot[_ -]?token|password)\s*[:=]\s*[^\s,;]+/giu, '$1=[凭据已隐藏]');
|
|
27
|
+
}
|
|
28
|
+
function localIntent(message) {
|
|
29
|
+
const text = message.normalize('NFKC').toLocaleLowerCase('zh-CN');
|
|
30
|
+
const metric = /胜率|吃鸡|冠军|夺冠|\bwin(?:s)?\b/iu.test(text)
|
|
31
|
+
? 'wins'
|
|
32
|
+
: /前\s*十|前十率|top\s*10/iu.test(text)
|
|
33
|
+
? 'top10'
|
|
34
|
+
: /救援|复活|\brevive(?:s)?\b/iu.test(text)
|
|
35
|
+
? 'revives'
|
|
36
|
+
: /倒地|击倒|\bknock(?:s)?\b/iu.test(text)
|
|
37
|
+
? 'knocks'
|
|
38
|
+
: /击杀|人头|\bkills?\b/iu.test(text)
|
|
39
|
+
? 'kills'
|
|
40
|
+
: /生存|存活时长|\bsurvival\b/iu.test(text)
|
|
41
|
+
? 'survival_time'
|
|
42
|
+
: /局数|多少场|比赛数|\bmatches\b/iu.test(text)
|
|
43
|
+
? 'matches'
|
|
44
|
+
: 'damage';
|
|
45
|
+
if (/telemetry|缓存覆盖|事件缓存|解析缓存/iu.test(text)) {
|
|
46
|
+
return { action: 'telemetry_coverage', metric: null, groupBy: null };
|
|
47
|
+
}
|
|
48
|
+
if (/打法|playstyle/iu.test(text) &&
|
|
49
|
+
/(近\s*(?:\d+|[零一二两三四五六七八九十]+)?\s*(?:场|局)|最近|last\s+\d+|\bplayer_[0-9]{2}\b)/iu.test(text)) {
|
|
50
|
+
return { action: 'player_comparison', metric, groupBy: 'player' };
|
|
51
|
+
}
|
|
52
|
+
if (/按地图|地图.*(比较|表现|胜率|伤害|击杀)|map.*(breakdown|compare)/iu.test(text)) {
|
|
53
|
+
return { action: 'map_breakdown', metric, groupBy: 'map' };
|
|
54
|
+
}
|
|
55
|
+
if (/队员|成员|谁.*(高|低|最好|最多)|比较|对比|player.*compare/iu.test(text)) {
|
|
56
|
+
return { action: 'player_comparison', metric, groupBy: 'player' };
|
|
57
|
+
}
|
|
58
|
+
if (/趋势|变化|走势|逐周|每周|trend|over\s+time/iu.test(text)) {
|
|
59
|
+
return { action: 'trend', metric, groupBy: 'week' };
|
|
60
|
+
}
|
|
61
|
+
if (/复盘|总结|概况|整体|表现|分析|\bsummary\b/iu.test(text))
|
|
62
|
+
return DEFAULT_INTENT;
|
|
63
|
+
if (!text.trim())
|
|
64
|
+
return { action: 'unsupported', metric: null, groupBy: null };
|
|
65
|
+
if (/pubg|比赛|对局|小队|队伍|队员|伤害|击杀|倒地|地图|排名|吃鸡|前十|战绩|比赛数据/iu.test(text))
|
|
66
|
+
return DEFAULT_INTENT;
|
|
67
|
+
return { action: 'unsupported', metric: null, groupBy: null };
|
|
68
|
+
}
|
|
69
|
+
const INTENT_INSTRUCTIONS = [
|
|
70
|
+
'Classify a PUBG squad research question into the one declared intent tool.',
|
|
71
|
+
'Return slots only. Do not answer, calculate, select a player, infer dates, or invent facts.',
|
|
72
|
+
'Use telemetry_coverage only for cache/parser coverage questions.',
|
|
73
|
+
'Use player_comparison for comparing squad members and map_breakdown for map grouping.',
|
|
74
|
+
'Use trend for change over time. Select groupBy week for trend, player for member comparison, map for map breakdown.',
|
|
75
|
+
'Metric meanings: wins is placement 1; top10 is placement 1 through 10; damage is match-store damage.',
|
|
76
|
+
'If the request is outside PUBG squad match research, return unsupported.',
|
|
77
|
+
].join('\n');
|
|
78
|
+
export class NaturalLanguageResearchPlanner {
|
|
79
|
+
model;
|
|
80
|
+
constructor(model) {
|
|
81
|
+
this.model = model;
|
|
82
|
+
if (model && typeof model === 'string')
|
|
83
|
+
throw new TypeError('An explicit language model instance is required');
|
|
84
|
+
}
|
|
85
|
+
async plan(message) {
|
|
86
|
+
const normalized = redactSensitiveText(message.trim());
|
|
87
|
+
if (this.model && normalized) {
|
|
88
|
+
try {
|
|
89
|
+
const result = await generateText({
|
|
90
|
+
model: this.model,
|
|
91
|
+
system: INTENT_INSTRUCTIONS,
|
|
92
|
+
prompt: `Untrusted research question as JSON: ${JSON.stringify(normalized)}`,
|
|
93
|
+
tools: {
|
|
94
|
+
submit_research_intent: tool({
|
|
95
|
+
description: 'Return the bounded research intent slots.',
|
|
96
|
+
inputSchema: ResearchIntentSchema,
|
|
97
|
+
}),
|
|
98
|
+
},
|
|
99
|
+
toolChoice: { type: 'tool', toolName: 'submit_research_intent' },
|
|
100
|
+
temperature: 0,
|
|
101
|
+
maxOutputTokens: 180,
|
|
102
|
+
maxRetries: 0,
|
|
103
|
+
});
|
|
104
|
+
const call = result.toolCalls.find((item) => item.toolName === 'submit_research_intent');
|
|
105
|
+
const parsed = ResearchIntentSchema.safeParse(call?.input);
|
|
106
|
+
if (parsed.success)
|
|
107
|
+
return { intent: parsed.data, source: 'ai-sdk' };
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Local classification keeps the research page usable without a model.
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { intent: localIntent(normalized), source: 'local-rule' };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function classifyResearchQuestion(message) {
|
|
117
|
+
return localIntent(message);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../../src/intent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type NormalizedMatch } from '@rine-kit/pubg-domain';
|
|
2
|
+
import { type DifferenceEstimate, type RateEstimate } from './analytics.js';
|
|
3
|
+
export declare const LANDING_SCHEMA_VERSION: 1;
|
|
4
|
+
export declare const LANDING_EARLY_WIPE_SECONDS = 420;
|
|
5
|
+
export declare const LANDING_CELL_KM = 1;
|
|
6
|
+
export interface LandingSample {
|
|
7
|
+
playerRef: string;
|
|
8
|
+
xMeters: number;
|
|
9
|
+
yMeters: number;
|
|
10
|
+
/** One-kilometre grid label such as C5 (column from west, row from north); null on maps of unknown size. */
|
|
11
|
+
cell: string | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function landingPlayerRef(accountId: string): string;
|
|
14
|
+
export declare function gridCell(xMeters: number, yMeters: number, mapName: string): string | null;
|
|
15
|
+
/** Reads LogParachuteLanding for the tracked squad; coordinates in telemetry are centimetres. */
|
|
16
|
+
export declare function extractLandings(payload: unknown, match: Pick<NormalizedMatch, 'mapName'>, memberIds: ReadonlySet<string>): LandingSample[];
|
|
17
|
+
export interface LandingMatchInput {
|
|
18
|
+
match: NormalizedMatch;
|
|
19
|
+
landings: readonly LandingSample[];
|
|
20
|
+
memberIds: ReadonlySet<string>;
|
|
21
|
+
/** Other teams that landed within the contest radius of the squad; null when unknown. */
|
|
22
|
+
contestedTeams?: number | null;
|
|
23
|
+
/** Named map area reported after landing. */
|
|
24
|
+
region?: string | null;
|
|
25
|
+
}
|
|
26
|
+
export interface LandingCellStats {
|
|
27
|
+
cell: string;
|
|
28
|
+
/** Most common named area for matches that used this cell. */
|
|
29
|
+
region: string | null;
|
|
30
|
+
matches: number;
|
|
31
|
+
share: number;
|
|
32
|
+
top10: RateEstimate;
|
|
33
|
+
medianPlacement: number | null;
|
|
34
|
+
earlyWipeRate: number | null;
|
|
35
|
+
averageDamage: number;
|
|
36
|
+
}
|
|
37
|
+
export interface LandingMapPreference {
|
|
38
|
+
mapName: string;
|
|
39
|
+
label: string;
|
|
40
|
+
sizeKm: number | null;
|
|
41
|
+
matches: number;
|
|
42
|
+
matchesWithLanding: number;
|
|
43
|
+
cells: LandingCellStats[];
|
|
44
|
+
/** Share of matches where the squad's main cell equals its most frequent main cell. */
|
|
45
|
+
topCellRepeatRate: number | null;
|
|
46
|
+
/** Median distance (m) between a member's landing and the squad centre. */
|
|
47
|
+
medianSpreadMeters: number | null;
|
|
48
|
+
points: Array<{
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
export interface ContestBucket {
|
|
54
|
+
key: string;
|
|
55
|
+
label: string;
|
|
56
|
+
matches: number;
|
|
57
|
+
top10: RateEstimate;
|
|
58
|
+
earlyWipe: RateEstimate;
|
|
59
|
+
medianPlacement: number | null;
|
|
60
|
+
}
|
|
61
|
+
export interface LandingContest {
|
|
62
|
+
matches: number;
|
|
63
|
+
buckets: ContestBucket[];
|
|
64
|
+
/** Early-wipe rate with at least one contesting team minus the rate with none. */
|
|
65
|
+
earlyWipeEdge: DifferenceEstimate;
|
|
66
|
+
top10Edge: DifferenceEstimate;
|
|
67
|
+
}
|
|
68
|
+
export interface LandingPreference {
|
|
69
|
+
schemaVersion: typeof LANDING_SCHEMA_VERSION;
|
|
70
|
+
maps: LandingMapPreference[];
|
|
71
|
+
contest: LandingContest;
|
|
72
|
+
notes: string[];
|
|
73
|
+
}
|
|
74
|
+
export declare function buildLandingPreference(inputs: readonly LandingMatchInput[]): LandingPreference;
|