koishi-plugin-chat-analyse 1.3.10 → 1.4.1
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/Data.d.ts +24 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +91 -11
- package/package.json +2 -2
- package/readme.md +93 -67
package/lib/Data.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Context, Command } from 'koishi';
|
|
2
|
+
/**
|
|
3
|
+
* @class Data
|
|
4
|
+
* @description 提供数据备份、恢复和清理等高级管理功能。
|
|
5
|
+
*/
|
|
6
|
+
export declare class Data {
|
|
7
|
+
private ctx;
|
|
8
|
+
private config;
|
|
9
|
+
private dataDir;
|
|
10
|
+
constructor(ctx: Context, config: any);
|
|
11
|
+
/**
|
|
12
|
+
* @private
|
|
13
|
+
* @method backupCache
|
|
14
|
+
* @description 备份 analyse_cache 表到 JSON 文件。
|
|
15
|
+
*/
|
|
16
|
+
private backupCache;
|
|
17
|
+
/**
|
|
18
|
+
* @public
|
|
19
|
+
* @method registerCommands
|
|
20
|
+
* @description 在主命令下注册所有数据管理相关的子命令。
|
|
21
|
+
* @param cmd - 主命令实例。
|
|
22
|
+
*/
|
|
23
|
+
registerCommands(cmd: Command): void;
|
|
24
|
+
}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1620,7 +1620,7 @@ var Renderer = class {
|
|
|
1620
1620
|
const { title, time, list } = data;
|
|
1621
1621
|
const CHUNK_SIZE = 100;
|
|
1622
1622
|
const totalItems = list.length;
|
|
1623
|
-
const countHeaderIndex = headers?.findIndex((
|
|
1623
|
+
const countHeaderIndex = headers?.findIndex((h7) => ["总计发言", "条数", "次数", "数量"].includes(h7)) ?? -1;
|
|
1624
1624
|
const totalCount = data.total || (countHeaderIndex > -1 ? list.reduce((sum, row) => sum + (Number(row[countHeaderIndex]) || 0), 0) : totalItems);
|
|
1625
1625
|
const renderCell = /* @__PURE__ */ __name((cell, i) => {
|
|
1626
1626
|
const headerText = headers?.[i] || "";
|
|
@@ -1668,7 +1668,7 @@ var Renderer = class {
|
|
|
1668
1668
|
<thead>
|
|
1669
1669
|
<tr>
|
|
1670
1670
|
<th class="rank-cell">#</th>
|
|
1671
|
-
${headers.map((
|
|
1671
|
+
${headers.map((h7) => `<th>${h7}</th>`).join("")}
|
|
1672
1672
|
</tr>
|
|
1673
1673
|
</thead>` : ""}
|
|
1674
1674
|
<tbody>
|
|
@@ -2104,16 +2104,51 @@ var import_koishi5 = require("koishi");
|
|
|
2104
2104
|
var fs = __toESM(require("fs/promises"));
|
|
2105
2105
|
var path = __toESM(require("path"));
|
|
2106
2106
|
var ALL_TABLES = ["analyse_user", "analyse_cmd", "analyse_msg", "analyse_rank", "analyse_at", "analyse_cache"];
|
|
2107
|
-
var
|
|
2107
|
+
var DEFAULT_BACKUP_TABLES = ["analyse_user", "analyse_cmd", "analyse_msg", "analyse_rank"];
|
|
2108
|
+
var BATCH_SIZE = 1e3;
|
|
2108
2109
|
var Data = class {
|
|
2109
|
-
constructor(ctx) {
|
|
2110
|
+
constructor(ctx, config) {
|
|
2110
2111
|
this.ctx = ctx;
|
|
2112
|
+
this.config = config;
|
|
2111
2113
|
this.dataDir = path.join(this.ctx.baseDir, "data", "chat-analyse");
|
|
2114
|
+
if (this.config.enableAutoBackup) this.ctx.cron("0 0 1 * *", () => {
|
|
2115
|
+
this.backupCache();
|
|
2116
|
+
});
|
|
2112
2117
|
}
|
|
2113
2118
|
static {
|
|
2114
2119
|
__name(this, "Data");
|
|
2115
2120
|
}
|
|
2116
2121
|
dataDir;
|
|
2122
|
+
/**
|
|
2123
|
+
* @private
|
|
2124
|
+
* @method backupCache
|
|
2125
|
+
* @description 备份 analyse_cache 表到 JSON 文件。
|
|
2126
|
+
*/
|
|
2127
|
+
async backupCache() {
|
|
2128
|
+
try {
|
|
2129
|
+
await fs.mkdir(this.dataDir, { recursive: true });
|
|
2130
|
+
const now = /* @__PURE__ */ new Date();
|
|
2131
|
+
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
2132
|
+
const year = lastMonth.getFullYear();
|
|
2133
|
+
const month = (lastMonth.getMonth() + 1).toString().padStart(2, "0");
|
|
2134
|
+
const filename = `analyse_cache_${year}-${month}.json`;
|
|
2135
|
+
const filepath = path.join(this.dataDir, filename);
|
|
2136
|
+
const allUsers = await this.ctx.database.get("analyse_user", {});
|
|
2137
|
+
if (allUsers.length === 0) return;
|
|
2138
|
+
const uidToUserInfoMap = new Map(allUsers.map((u) => [u.uid, u]));
|
|
2139
|
+
const records = await this.ctx.database.get("analyse_cache", {});
|
|
2140
|
+
if (records.length === 0) return;
|
|
2141
|
+
const dataToExport = records.map((record) => {
|
|
2142
|
+
const userInfo = uidToUserInfoMap.get(record.uid);
|
|
2143
|
+
if (!userInfo) return null;
|
|
2144
|
+
const { id, uid, ...restOfRecord } = record;
|
|
2145
|
+
return { userId: userInfo.userId, channelId: userInfo.channelId, ...restOfRecord };
|
|
2146
|
+
}).filter(Boolean);
|
|
2147
|
+
await fs.writeFile(filepath, JSON.stringify(dataToExport, null, 2));
|
|
2148
|
+
} catch (error) {
|
|
2149
|
+
this.ctx.logger.error("原始记录备份失败:", error);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2117
2152
|
/**
|
|
2118
2153
|
* @public
|
|
2119
2154
|
* @method registerCommands
|
|
@@ -2121,12 +2156,13 @@ var Data = class {
|
|
|
2121
2156
|
* @param cmd - 主命令实例。
|
|
2122
2157
|
*/
|
|
2123
2158
|
registerCommands(cmd) {
|
|
2124
|
-
cmd.subcommand(".backup", "备份数据", { authority: 4 }).usage("
|
|
2159
|
+
cmd.subcommand(".backup", "备份数据", { authority: 4 }).usage("将统计数据导出为 JSON 文件,并保存到本地。").option("all", "-a 全量备份").action(async ({ options }) => {
|
|
2160
|
+
const tablesToProcess = options.all ? ALL_TABLES : DEFAULT_BACKUP_TABLES;
|
|
2125
2161
|
try {
|
|
2126
2162
|
await fs.mkdir(this.dataDir, { recursive: true });
|
|
2127
2163
|
const allUsers = await this.ctx.database.get("analyse_user", {});
|
|
2128
2164
|
const uidToUserInfoMap = new Map(allUsers.map((u) => [u.uid, u]));
|
|
2129
|
-
for (const tableName of
|
|
2165
|
+
for (const tableName of tablesToProcess) {
|
|
2130
2166
|
const filepath = path.join(this.dataDir, `${tableName}.json`);
|
|
2131
2167
|
let dataToExport;
|
|
2132
2168
|
if (tableName === "analyse_user") {
|
|
@@ -2148,14 +2184,15 @@ var Data = class {
|
|
|
2148
2184
|
return "数据备份失败";
|
|
2149
2185
|
}
|
|
2150
2186
|
});
|
|
2151
|
-
cmd.subcommand(".restore", "恢复数据", { authority: 4 }).usage(
|
|
2187
|
+
cmd.subcommand(".restore", "恢复数据", { authority: 4 }).usage("从本地的 JSON 文件中恢复统计数据。").option("all", "-a 全量恢复").action(async ({ options }) => {
|
|
2152
2188
|
try {
|
|
2153
2189
|
const userTablePath = path.join(this.dataDir, "analyse_user.json");
|
|
2154
2190
|
const usersToImport = JSON.parse(await fs.readFile(userTablePath, "utf-8").catch(() => "[]"));
|
|
2155
2191
|
if (usersToImport.length) for (let i = 0; i < usersToImport.length; i += BATCH_SIZE) await this.ctx.database.upsert("analyse_user", usersToImport.slice(i, i + BATCH_SIZE));
|
|
2156
2192
|
const allUsers = await this.ctx.database.get("analyse_user", {});
|
|
2157
2193
|
const userToUidMap = new Map(allUsers.map((u) => [`${u.channelId}:${u.userId}`, u.uid]));
|
|
2158
|
-
|
|
2194
|
+
const tablesToProcess = options.all ? ALL_TABLES.filter((t) => t !== "analyse_user") : DEFAULT_BACKUP_TABLES.filter((t) => t !== "analyse_user");
|
|
2195
|
+
for (const tableName of tablesToProcess) {
|
|
2159
2196
|
const filepath = path.join(this.dataDir, `${tableName}.json`);
|
|
2160
2197
|
const recordsToImport = JSON.parse(await fs.readFile(filepath, "utf-8").catch(() => "[]"));
|
|
2161
2198
|
if (!recordsToImport.length) continue;
|
|
@@ -2243,6 +2280,48 @@ var Data = class {
|
|
|
2243
2280
|
return "数据清理失败";
|
|
2244
2281
|
}
|
|
2245
2282
|
});
|
|
2283
|
+
if (this.config.enableOriRecord) {
|
|
2284
|
+
cmd.subcommand(".view <time:string>", "查询消息记录", { authority: 4 }).usage("查询指定时间点后的消息记录,默认查询当前群组。").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").action(async ({ session, options }, time) => {
|
|
2285
|
+
if (!time) return '请以"YYYY-MM-DD HH:MM:SS"格式输入起始时间';
|
|
2286
|
+
const since = new Date(time);
|
|
2287
|
+
if (isNaN(since.getTime())) return "时间格式无效";
|
|
2288
|
+
try {
|
|
2289
|
+
const userQuery = {};
|
|
2290
|
+
if (!options.guild && !options.user) {
|
|
2291
|
+
if (!session.guildId) return "请指定查询范围";
|
|
2292
|
+
userQuery.channelId = session.guildId;
|
|
2293
|
+
} else {
|
|
2294
|
+
if (options.guild) userQuery.channelId = options.guild;
|
|
2295
|
+
if (options.user) userQuery.userId = import_koishi5.Element.select(options.user, "at")[0]?.attrs.id ?? options.user;
|
|
2296
|
+
}
|
|
2297
|
+
const usersInScope = await this.ctx.database.get("analyse_user", userQuery);
|
|
2298
|
+
if (usersInScope.length === 0) return "暂无用户数据";
|
|
2299
|
+
const uids = usersInScope.map((u) => u.uid);
|
|
2300
|
+
const records = await this.ctx.database.get("analyse_cache", {
|
|
2301
|
+
uid: { $in: uids },
|
|
2302
|
+
timestamp: { $gte: since }
|
|
2303
|
+
}, {
|
|
2304
|
+
sort: { timestamp: "asc" },
|
|
2305
|
+
limit: 100
|
|
2306
|
+
});
|
|
2307
|
+
if (records.length === 0) return "暂无统计数据";
|
|
2308
|
+
const recordUids = [...new Set(records.map((r) => r.uid))];
|
|
2309
|
+
const users = await this.ctx.database.get("analyse_user", { uid: { $in: recordUids } }, ["uid", "userName", "userId"]);
|
|
2310
|
+
const userInfoMap = new Map(users.map((u) => [u.uid, { name: u.userName, id: u.userId }]));
|
|
2311
|
+
const messageElements = records.map((record) => {
|
|
2312
|
+
const senderInfo = userInfoMap.get(record.uid) || { name: `UID ${record.uid}`, id: "unknown" };
|
|
2313
|
+
const timeStr = record.timestamp.toLocaleTimeString("zh-CN", { hour12: false });
|
|
2314
|
+
const author = (0, import_koishi5.h)("author", { id: senderInfo.id, name: senderInfo.name });
|
|
2315
|
+
const content = import_koishi5.h.text(`[${timeStr}] ${record.content}`);
|
|
2316
|
+
return (0, import_koishi5.h)("message", {}, [author, content]);
|
|
2317
|
+
});
|
|
2318
|
+
await session.send((0, import_koishi5.h)("message", { forward: true }, messageElements));
|
|
2319
|
+
} catch (error) {
|
|
2320
|
+
this.ctx.logger.error("查询消息记录失败:", error);
|
|
2321
|
+
return "查询消息记录失败";
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2246
2325
|
cmd.subcommand(".list", "列出数据", { authority: 4 }).usage("列出数据库中的频道和命令列表。").action(async () => {
|
|
2247
2326
|
const [allChannelInfo, commands] = await Promise.all([
|
|
2248
2327
|
this.ctx.database.get("analyse_user", {}, ["channelId", "channelName"]),
|
|
@@ -2429,13 +2508,14 @@ var Config3 = import_koishi7.Schema.intersect([
|
|
|
2429
2508
|
enableMsgStat: import_koishi7.Schema.boolean().default(true).description("启用消息统计"),
|
|
2430
2509
|
enableActivity: import_koishi7.Schema.boolean().default(true).description("启用活跃统计"),
|
|
2431
2510
|
enableRankStat: import_koishi7.Schema.boolean().default(true).description("启用发言排行"),
|
|
2432
|
-
rankRetentionDays: import_koishi7.Schema.number().min(0).default(
|
|
2511
|
+
rankRetentionDays: import_koishi7.Schema.number().min(0).default(365).description("排行保留天数"),
|
|
2433
2512
|
enableWhoAt: import_koishi7.Schema.boolean().default(true).description("启用提及记录"),
|
|
2434
2513
|
atRetentionDays: import_koishi7.Schema.number().min(0).default(3).description("提及保留天数")
|
|
2435
2514
|
}).description("基础分析配置"),
|
|
2436
2515
|
import_koishi7.Schema.object({
|
|
2437
2516
|
enableOriRecord: import_koishi7.Schema.boolean().default(true).description("启用原始记录"),
|
|
2438
|
-
cacheRetentionDays: import_koishi7.Schema.number().min(0).default(
|
|
2517
|
+
cacheRetentionDays: import_koishi7.Schema.number().min(0).default(31).description("记录保留天数"),
|
|
2518
|
+
enableAutoBackup: import_koishi7.Schema.boolean().default(false).description("启用自动备份"),
|
|
2439
2519
|
enableWordCloud: import_koishi7.Schema.boolean().default(true).description("启用词云生成"),
|
|
2440
2520
|
enableSimilarActivity: import_koishi7.Schema.boolean().default(true).description("启用相似活跃分析")
|
|
2441
2521
|
}).description("高级分析配置")
|
|
@@ -2483,7 +2563,7 @@ function apply(ctx, config) {
|
|
|
2483
2563
|
const analyse = ctx.command("analyse", "数据分析");
|
|
2484
2564
|
new Stat(ctx, config).registerCommands(analyse);
|
|
2485
2565
|
if (config.enableWhoAt) new WhoAt(ctx, config).registerCommand(analyse);
|
|
2486
|
-
if (config.enableDataIO) new Data(ctx).registerCommands(analyse);
|
|
2566
|
+
if (config.enableDataIO) new Data(ctx, config).registerCommands(analyse);
|
|
2487
2567
|
if (config.enableWordCloud || config.enableSimilarActivity) new Analyse(ctx, config).registerCommands(analyse);
|
|
2488
2568
|
}
|
|
2489
2569
|
__name(apply, "apply");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-chat-analyse",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "1.
|
|
3
|
+
"description": "强大而全面的聊天数据分析插件。支持多维度统计(命令、发言、消息类型、活跃度),可生成发言排行、词云图,并提供完善的数据管理。",
|
|
4
|
+
"version": "1.4.1",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Yis_Rime <yis_rime@outlook.com>"
|
|
7
7
|
],
|
package/readme.md
CHANGED
|
@@ -2,33 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/koishi-plugin-chat-analyse)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
强大而全面的聊天数据分析插件。支持多维度统计(命令、发言、消息类型、活跃度),可生成发言排行、词云图,并提供完善的数据管理。
|
|
6
6
|
|
|
7
7
|
## ✨ 功能特性
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
**高效数据收集**:采用异步、高并发和缓存机制,在不影响机器人性能的前提下,精确高效地收集聊天数据。
|
|
10
|
+
**多维度统计分析**:
|
|
11
|
+
**命令统计** (`cmdstat`):追踪指令使用频率,了解用户最常用的功能,支持按次数或时间排序。
|
|
12
|
+
**发言统计** (`msgstat`):分析用户发言类型与数量,掌握核心用户群体,支持按条数或时间排序。
|
|
13
|
+
**发言排行** (`rankstat`):生成指定时间范围内的用户发言排行榜,发掘群聊中的“龙王”。
|
|
14
|
+
**活跃度分析** (`activity`):以小时或天为单位,生成直观的周期性活跃度图表,洞察社群活跃时段。
|
|
15
|
+
**高级文本分析**:
|
|
16
|
+
**词云生成** (`wordcloud`):基于聊天记录,利用 Jieba 分词生成热门话题词云图,快速了解近期热点。
|
|
17
|
+
**相似活跃分析** (`simiactive`): 分析指定时间内,找出与您作息模式最相似的群友,并通过对比图表直观展示。
|
|
18
|
+
**提及追踪** (`whoatme`):轻松查询谁在什么时候因为什么内容提及了您,不再错过重要信息。
|
|
19
|
+
**强大的数据管理**:
|
|
20
|
+
**备份与恢复** (`.backup`/`.restore`):一键备份所有统计数据至本地,并可随时恢复,保障数据安全。
|
|
21
|
+
**精确清理** (`.clear`):提供多维度的筛选条件(如按时间、用户、群组、发言数),精确清理不再需要的数据。
|
|
22
|
+
**记录查看** (`.view`): 可回溯查看指定时间点后的原始消息记录。
|
|
23
|
+
**精美图表渲染**:借助 Puppeteer 服务,将复杂的统计数据渲染成美观、易读的图片,方便在聊天中分享。
|
|
24
|
+
**高度可配置**:所有功能模块均可独立开关,并可自定义数据保留时长等核心参数,以适应不同场景的需求。
|
|
24
25
|
|
|
25
26
|
## ⚙️ 前置服务
|
|
26
27
|
|
|
27
28
|
本插件依赖以下 Koishi 服务,请确保您已正确安装并启用了它们:
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
**`database`**:用于存储所有统计分析数据。
|
|
31
|
+
**`puppeteer`**:用于将统计结果渲染成图片。
|
|
32
|
+
**`cron`**:用于执行数据定时清理任务。
|
|
32
33
|
|
|
33
34
|
## 📝 使用说明
|
|
34
35
|
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
### 指令列表
|
|
38
39
|
|
|
39
40
|
| 指令 | 别名 | 描述 | 选项 |
|
|
40
|
-
|
|
|
41
|
+
| :--| :--| :--| :--|
|
|
41
42
|
| `cmdstat` | 命令统计 | 查询命令使用情况,展示方式根据选项变化 | `-u`, `-g`, `-a`, `-p`, `-s` |
|
|
42
43
|
| `msgstat` | 发言统计 | 查询用户发言统计,展示方式根据选项变化 | `-u`, `-g`, `-a`, `-t`, `-s` |
|
|
43
44
|
| `rankstat` | 发言排行 | 查询指定时间内的发言排行 | `-u`, `-g`, `-a`, `-t`, `-n`, `-o` |
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
| `wordcloud` | 生成词云 | 基于聊天记录生成词云图 | `-u`, `-g`, `-t` |
|
|
46
47
|
| `simiactive`| 相似活跃分析 | 分析并找出与您作息相似的群友 | `-n`, `-p` |
|
|
47
48
|
| `whoatme` | 谁提及我 | 查看最近谁提及了您 | (无) |
|
|
49
|
+
| `analyse.view <time>`| 查询记录 | (管理) 查询指定时间点后的消息记录 | `-u`, `-g` |
|
|
48
50
|
| `analyse.list` | 列出数据 | (管理) 列出已记录的频道和命令 | (无) |
|
|
49
51
|
| `analyse.backup` | 备份数据 | (管理) 将所有数据备份为本地 JSON 文件 | (无) |
|
|
50
52
|
| `analyse.restore` | 恢复数据 | (管理) 从本地 JSON 文件恢复数据 | (无) |
|
|
@@ -52,57 +54,78 @@
|
|
|
52
54
|
|
|
53
55
|
**通用选项说明:**
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
`-u, --user <user>`: 指定用户 (可使用 @ 或 userID)。
|
|
58
|
+
`-g, --guild <guild>`: 指定群组 (需使用群组ID)。
|
|
59
|
+
`-a, --all`: 查询全局数据。
|
|
58
60
|
|
|
59
61
|
### 🔎 指令详解
|
|
60
62
|
|
|
61
63
|
#### `cmdstat` (命令统计)
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
**`cmdstat`**: 查询**当前群组**所有用户的命令统计。
|
|
66
|
+
**`cmdstat -u @用户`**: 查询**指定用户**在**所有群组**的命令统计。
|
|
67
|
+
**`cmdstat -g <群组ID>`**: 查询**指定群组**所有用户的命令统计。
|
|
68
|
+
**`cmdstat -u @用户 -g <群组ID>`**: 查询**指定用户**在**指定群组**的命令统计。
|
|
69
|
+
**`cmdstat -a`**: 查询**全局**(所有用户+所有群组)的命令统计。
|
|
70
|
+
**选项 `-p, --separate`**: 分离展示子命令,不合并到主命令。
|
|
71
|
+
**选项 `-s, --sortByTime`**: 按最后使用时间降序排序(默认按使用次数)。
|
|
70
72
|
|
|
71
73
|
#### `msgstat` (发言统计)
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
**`msgstat`**: 查询**当前群组**的发言统计 (按**用户**展示)。
|
|
76
|
+
**`msgstat -u @用户`**: 查询**指定用户**的发言统计 (按**群组**展示)。
|
|
77
|
+
**`msgstat -g <群组ID>`**: 查询**指定群组**的发言统计 (按**用户**展示)。
|
|
78
|
+
**`msgstat -u @用户 -g <群组ID>`**: 查询**指定用户**在**指定群组**的发言统计 (按**消息类型**展示)。
|
|
79
|
+
**`msgstat -a`**: 查询**全局**发言统计 (按**用户**展示)。
|
|
80
|
+
**选项 `-t, --type <类型>`**: 筛选指定消息类型 (`text`, `face`, `image` 等),不改变上述展示逻辑。
|
|
81
|
+
**选项 `-s, --sortByTime`**: 按最后发言时间降序排序(默认按发言条数)。
|
|
80
82
|
|
|
81
83
|
#### `rankstat` (发言排行)
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
**`rankstat`**: 查询**当前群组**的发言排行 (按**用户**排名)。
|
|
86
|
+
**`rankstat -u @用户`**: 查询**指定用户**的发言排行 (按**群组**排名)。
|
|
87
|
+
**`rankstat -u @用户 -g <群组ID>`**: 查询**指定用户**在**指定群组**的发言排行 (按**消息类型**排名)。
|
|
88
|
+
**`rankstat -a`**: 查询**全局**发言排行 (按**用户**排名)。
|
|
89
|
+
**选项 `-n, --duration <小时数>`**: 指定查询范围的时长,默认为 `24`。
|
|
90
|
+
**选项 `-o, --offset <小时数>`**: 指定查询结束时间的偏移量(从现在往前推的小时数),默认为 `0`。
|
|
91
|
+
**选项 `-t, --type <类型>`...**: 筛选指定消息类型。
|
|
90
92
|
|
|
91
93
|
#### `activity` (活跃统计)
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
**`activity`**: 查询**当前群组**的活跃度。
|
|
96
|
+
**`activity -a`**: 查询**全局**活跃度。
|
|
97
|
+
**`activity -u @用户 -g <群组ID>`**: 查询**指定用户**在**指定群组**的活跃度。
|
|
98
|
+
**选项 `-n, --duration <数值>`**: 指定查询范围的时长,默认为 `24`。
|
|
99
|
+
**选项 `-o, --offset <数值>`**: 指定查询结束时间的偏移量,默认为 `0`。
|
|
100
|
+
**选项 `-d, --days`**: 将 `-n` 和 `-o` 的单位从**小时**切换为**天**。
|
|
101
|
+
|
|
102
|
+
#### `wordcloud` (生成词云)
|
|
103
|
+
|
|
104
|
+
**`wordcloud`**: 基于**当前群组**最近 `24` 小时聊天记录生成词云。
|
|
105
|
+
**选项 `-u, --user <user>`**: 指定用户。
|
|
106
|
+
**选项 `-g, --guild <guild>`**: 指定群组。
|
|
107
|
+
**选项 `-t, --hours <小时数>`**: 指定查询时长,默认为 `24`。
|
|
99
108
|
|
|
100
109
|
#### `simiactive` (相似活跃分析)
|
|
101
110
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
**`simiactive`**: 在**当前群组**中,分析最近 **24 小时**内与您作息最相似的群友。
|
|
112
|
+
**`simiactive -n 48`**: 指定分析最近 **48 小时**的数据。
|
|
113
|
+
**选项 `-n, --hours <小时数>`**: 指定查询范围的时长,默认为 `24`。
|
|
114
|
+
**选项 `-p, --separate`**: 分离小时数据,不按天聚合进行分析。
|
|
115
|
+
|
|
116
|
+
#### `analyse.clear` (清除数据)
|
|
117
|
+
|
|
118
|
+
该指令用于高级数据管理,请谨慎使用。
|
|
119
|
+
|
|
120
|
+
| 选项 | 别名 | 描述 |
|
|
121
|
+
| :--| :--| :--|
|
|
122
|
+
| `--table <表名>` | `-t` | 指定要清除的表名 (如 `analyse_cmd`)。若不指定,则默认清理除 `analyse_user` 外的所有表。 |
|
|
123
|
+
| `--guild <群组ID>` | `-g` | 仅清除指定群组的数据。 |
|
|
124
|
+
| `--user <用户>` | `-u` | 仅清除指定用户的数据。 |
|
|
125
|
+
| `--days <天数>` | `-d` | 清除指定天数之前的所有数据 (例如 `-d 30` 会删除30天前的数据)。 |
|
|
126
|
+
| `--command <命令>` | `-c` | 仅清除 `analyse_cmd` 表中指定的命令记录。 |
|
|
127
|
+
| `--limit <次数>` | `-l` | 清除总发言数小于指定次数的用户的所有记录。 |
|
|
128
|
+
| `--all` | `-a` | **【高危】** 清除插件产生的所有数据表,相当于重置插件。 |
|
|
106
129
|
|
|
107
130
|
## 🔧 配置项
|
|
108
131
|
|
|
@@ -110,25 +133,28 @@
|
|
|
110
133
|
|
|
111
134
|
### 杂项配置
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
136
|
+
`enableListener`: **启用消息监听**。总开关,关闭后插件将停止所有数据收集。 (默认: `true`)
|
|
137
|
+
`enableDataIO`: **启用数据管理**。控制 `.backup`, `.restore`, `.clear`, `.list`, `.view` 等管理指令的可用性。 (默认: `true`)
|
|
115
138
|
|
|
116
139
|
### 基础分析配置
|
|
117
140
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
`enableCmdStat`: **启用命令统计**。 (默认: `true`)
|
|
142
|
+
`enableMsgStat`: **启用消息统计**。 (默认: `true`)
|
|
143
|
+
`enableActivity`: **启用活跃统计**。 (默认: `true`)
|
|
144
|
+
`enableRankStat`: **启用发言排行**。 (默认: `true`)
|
|
145
|
+
`rankRetentionDays`: **排行保留天数**。发言排行数据的保留时长(天),`0` 为永久保留。 (默认: `180`)
|
|
146
|
+
`enableWhoAt`: **启用提及记录**。 (默认: `true`)
|
|
147
|
+
`atRetentionDays`: **提及保留天数**。`whoatme` 数据的保留时长(天),`0` 为永久保留。 (默认: `3`)
|
|
125
148
|
|
|
126
149
|
### 高级分析配置
|
|
127
150
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
151
|
+
`enableOriRecord`: **启用原始记录**。是否记录原始消息内容。这是 `.view` 和 `wordcloud` 功能的基础。 (默认: `true`)
|
|
152
|
+
`cacheRetentionDays`: **原始记录保留天数**。原始消息记录的保留时长(天),`0` 为永久保留。 (默认: `30`)
|
|
153
|
+
`enableAutoBackup`: **启用自动备份记录**。是否开启每月自动备份原始消息记录。 (默认: `false`)
|
|
154
|
+
`enableWordCloud`: **启用词云生成**。
|
|
155
|
+
> **!** 此功能依赖 **`启用原始记录`**。 (默认: `true`)
|
|
156
|
+
`enableSimilarActivity`: **启用相似活跃分析**。
|
|
157
|
+
> **!** 此功能依赖 **`启用发言排行`** 或 **`启用活跃统计`**。 (默认: `true`)
|
|
132
158
|
|
|
133
159
|
## 📌 注意事项
|
|
134
160
|
|