koishi-plugin-chat-analyse 1.3.6 → 1.3.7
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/lib/index.js +51 -49
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1697,7 +1697,7 @@ var Renderer = class {
|
|
|
1697
1697
|
const selectedPalette = colorfulPalettes[Math.floor(Math.random() * colorfulPalettes.length)];
|
|
1698
1698
|
const shuffledColors = [...selectedPalette].sort(() => 0.5 - Math.random());
|
|
1699
1699
|
const seriesColors = series.map((_, index) => shuffledColors[index % shuffledColors.length]);
|
|
1700
|
-
const width = 600, height =
|
|
1700
|
+
const width = 600, height = 320;
|
|
1701
1701
|
const padding = { top: 15, right: 15, bottom: 60, left: 25 };
|
|
1702
1702
|
const chartWidth = width - padding.left - padding.right;
|
|
1703
1703
|
const chartHeight = height - padding.top - padding.bottom;
|
|
@@ -2318,64 +2318,66 @@ var Analyse = class {
|
|
|
2318
2318
|
});
|
|
2319
2319
|
}
|
|
2320
2320
|
if (this.config.enableSimilarActivity) {
|
|
2321
|
-
cmd.subcommand("simiactive", "相似活跃分析").usage("
|
|
2321
|
+
cmd.subcommand("simiactive", "相似活跃分析").usage("分析你和群友的活跃规律,找出谁和你的作息最相似。").option("hours", "-n <hours:number> 指定时长", { fallback: 24 }).option("separate", "-p 分时分析").action(async ({ session, options }) => {
|
|
2322
2322
|
if (!session.guildId) return "请在群组中使用此命令";
|
|
2323
2323
|
try {
|
|
2324
|
-
const until = /* @__PURE__ */ new Date();
|
|
2325
|
-
let since;
|
|
2326
|
-
let points;
|
|
2327
|
-
let title;
|
|
2328
|
-
let labels;
|
|
2329
|
-
let daysToAnalyze = 0;
|
|
2330
|
-
if (options.separate) {
|
|
2331
|
-
points = options.hours;
|
|
2332
|
-
since = new Date(until.getTime() - options.hours * import_koishi6.Time.hour);
|
|
2333
|
-
title = `${options.hours}小时相似活跃分析`;
|
|
2334
|
-
labels = Array.from({ length: points }, (_, i) => String(new Date(until.getTime() - (points - 1 - i) * import_koishi6.Time.hour).getHours()));
|
|
2335
|
-
} else {
|
|
2336
|
-
daysToAnalyze = Math.floor(options.hours / 24);
|
|
2337
|
-
if (daysToAnalyze < 1) return "请指定至少 24 小时时长";
|
|
2338
|
-
const analysisDurationHours = daysToAnalyze * 24;
|
|
2339
|
-
since = new Date(until.getTime() - analysisDurationHours * import_koishi6.Time.hour);
|
|
2340
|
-
points = 24;
|
|
2341
|
-
title = `${daysToAnalyze}天相似活跃分析`;
|
|
2342
|
-
labels = Array.from({ length: 24 }, (_, i) => String(i));
|
|
2343
|
-
}
|
|
2344
2324
|
const guildUsers = await this.ctx.database.get("analyse_user", { channelId: session.guildId });
|
|
2345
2325
|
if (guildUsers.length < 2) return "暂无用户数据";
|
|
2346
2326
|
const selfUser = guildUsers.find((u) => u.userId === session.userId);
|
|
2347
2327
|
const guildUserUids = guildUsers.map((u) => u.uid);
|
|
2348
2328
|
const uidToNameMap = new Map(guildUsers.map((u) => [u.uid, u.userName]));
|
|
2349
|
-
const
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2329
|
+
const until = /* @__PURE__ */ new Date();
|
|
2330
|
+
let analysisConfig;
|
|
2331
|
+
if (options.separate) {
|
|
2332
|
+
const { hours } = options;
|
|
2333
|
+
analysisConfig = {
|
|
2334
|
+
points: hours,
|
|
2335
|
+
since: new Date(until.getTime() - hours * import_koishi6.Time.hour),
|
|
2336
|
+
title: `${hours}小时相似活跃分析`,
|
|
2337
|
+
labels: Array.from({ length: hours }, (_, i) => String(new Date(until.getTime() - (hours - 1 - i) * import_koishi6.Time.hour).getHours())),
|
|
2338
|
+
getIndex: /* @__PURE__ */ __name((timestamp) => {
|
|
2339
|
+
const diff = until.getTime() - timestamp.getTime();
|
|
2340
|
+
const index = hours - 1 - Math.floor(diff / import_koishi6.Time.hour);
|
|
2341
|
+
return index >= 0 && index < hours ? index : -1;
|
|
2342
|
+
}, "getIndex"),
|
|
2343
|
+
reorderVector: /* @__PURE__ */ __name((vec) => vec, "reorderVector")
|
|
2344
|
+
};
|
|
2345
|
+
} else {
|
|
2346
|
+
const daysToAnalyse = Math.floor(options.hours / 24);
|
|
2347
|
+
if (daysToAnalyse < 1) return "分析时长请指定至少 1 天";
|
|
2348
|
+
const hoursToAnalyse = daysToAnalyse * 24;
|
|
2349
|
+
const currentHour = until.getHours();
|
|
2350
|
+
const labels = Array.from({ length: 24 }, (_, i) => String((currentHour - (23 - i) + 24) % 24));
|
|
2351
|
+
analysisConfig = {
|
|
2352
|
+
points: 24,
|
|
2353
|
+
since: new Date(until.getTime() - hoursToAnalyse * import_koishi6.Time.hour),
|
|
2354
|
+
title: `${daysToAnalyse}天相似活跃分析`,
|
|
2355
|
+
labels,
|
|
2356
|
+
getIndex: /* @__PURE__ */ __name((timestamp) => timestamp.getHours(), "getIndex"),
|
|
2357
|
+
reorderVector: /* @__PURE__ */ __name((vector) => labels.map((label) => vector[parseInt(label)]), "reorderVector")
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
const records = await this.ctx.database.get("analyse_rank", { uid: { $in: guildUserUids }, timestamp: { $gte: analysisConfig.since } });
|
|
2361
|
+
if (!records.length) return "暂无统计数据";
|
|
2362
|
+
const activityVectors = new Map(guildUserUids.map((uid) => [uid, Array(analysisConfig.points).fill(0)]));
|
|
2363
|
+
for (const record of records) {
|
|
2364
|
+
const index = analysisConfig.getIndex(record.timestamp);
|
|
2365
|
+
if (index !== -1) activityVectors.get(record.uid)[index] += record.count;
|
|
2366
|
+
}
|
|
2368
2367
|
const selfVector = activityVectors.get(selfUser.uid);
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2368
|
+
const similarities = guildUserUids.filter((uid) => uid !== selfUser.uid && activityVectors.get(uid).some((v) => v !== 0)).map((uid) => ({
|
|
2369
|
+
uid,
|
|
2370
|
+
score: cosineSimilarity(selfVector, activityVectors.get(uid))
|
|
2371
|
+
})).sort((a, b) => b.score - a.score);
|
|
2372
|
+
if (!similarities.length) return "暂无相似用户";
|
|
2372
2373
|
const top5 = similarities.slice(0, 5);
|
|
2373
|
-
const series = [{ name: uidToNameMap.get(selfUser.uid) || "您", data: selfVector }];
|
|
2374
|
-
|
|
2374
|
+
const series = [{ name: uidToNameMap.get(selfUser.uid) || "您", data: analysisConfig.reorderVector(selfVector) }];
|
|
2375
|
+
for (const sim of top5) {
|
|
2375
2376
|
const name2 = uidToNameMap.get(sim.uid) || `UID ${sim.uid}`;
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2377
|
+
const data = analysisConfig.reorderVector(activityVectors.get(sim.uid));
|
|
2378
|
+
series.push({ name: `${name2} (${(sim.score * 100).toFixed(1)}%)`, data });
|
|
2379
|
+
}
|
|
2380
|
+
const imageGenerator = this.renderer.renderLineChart({ title: analysisConfig.title, time: /* @__PURE__ */ new Date(), series, labels: analysisConfig.labels });
|
|
2379
2381
|
for await (const buffer of imageGenerator) await session.send(import_koishi6.h.image(buffer, "image/png"));
|
|
2380
2382
|
} catch (error) {
|
|
2381
2383
|
this.ctx.logger.error("生成作息分析图片失败:", error);
|