koishi-plugin-chat-analyse 0.6.3 → 0.7.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/lib/Analyse.d.ts CHANGED
@@ -5,18 +5,20 @@ export interface WordCloudData {
5
5
  time: Date;
6
6
  words: [string, number][];
7
7
  }
8
+ /**
9
+ * @class Analyse
10
+ * @description 提供文本分析功能,如生成词云。
11
+ */
8
12
  export declare class Analyse {
9
13
  private ctx;
10
14
  private config;
11
15
  private renderer;
12
- private nlp;
13
- private isNlpReady;
16
+ private readonly jieba;
14
17
  constructor(ctx: Context, config: Config);
15
18
  /**
16
- * @private
17
- * @method initializeNlp
18
- * @description 异步加载并训练 NLP 模型。
19
+ * @public @method registerCommands
20
+ * @description 在主命令下注册子命令。
21
+ * @param cmd - 主命令实例。
19
22
  */
20
- private initializeNlp;
21
23
  registerCommands(cmd: Command): void;
22
24
  }
package/lib/Renderer.d.ts CHANGED
@@ -19,6 +19,7 @@ export interface CircadianChartData {
19
19
  time: Date;
20
20
  total: string | number;
21
21
  data: number[];
22
+ labels?: string[];
22
23
  }
23
24
  /**
24
25
  * @class Renderer
package/lib/index.d.ts CHANGED
@@ -19,7 +19,6 @@ export interface Config {
19
19
  atRetentionDays: number;
20
20
  rankRetentionDays: number;
21
21
  enableWordCloud: boolean;
22
- enableVocabulary: boolean;
23
22
  }
24
23
  /** @description 插件的配置项定义 */
25
24
  export declare const Config: Schema<Config>;
@@ -54,6 +53,7 @@ export declare function generateTitle(ctx: Context, scopeDesc: {
54
53
  main: string;
55
54
  subtype?: string;
56
55
  timeRange?: number;
56
+ timeUnit?: '小时' | '天';
57
57
  }): Promise<string>;
58
58
  /**
59
59
  * @function apply
package/lib/index.js CHANGED
@@ -425,16 +425,15 @@ var Renderer = class {
425
425
  * @returns {Promise<string | Buffer[]>} - 成功时返回包含图片 Buffer 的数组,失败或无数据时返回提示字符串。
426
426
  */
427
427
  async renderCircadianChart(data) {
428
- const { title, time, total, data: hourlyCounts } = data;
428
+ const { title, time, total, data: hourlyCounts, labels } = data;
429
429
  if (!hourlyCounts || hourlyCounts.every((c) => c === 0)) return "暂无数据可供渲染";
430
430
  const maxCount = Math.max(...hourlyCounts, 1);
431
431
  const chartStyles = `
432
432
  .chart-container { display: flex; align-items: flex-end; gap: 4px; height: 180px; padding: 30px 15px 10px; }
433
433
  .bar-wrapper { flex: 1; text-align: center; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
434
- .bar-value { font-size: 11px; color: var(--sub-text-color); height: 16px; line-height: 16px; font-weight: 500; visibility: ${maxCount > 50 ? "hidden" : "visible"}; }
434
+ .bar-value { font-size: 11px; color: var(--sub-text-color); height: 16px; line-height: 16px; font-weight: 500; }
435
435
  .bar-container { flex-grow: 1; display: flex; align-items: flex-end; width: 100%; }
436
436
  .bar { width: 100%; background-color: var(--accent-color); opacity: .7; border-radius: 3px 3px 0 0; transition: height .3s ease-out; }
437
- .bar.peak { opacity: 1; background-color: var(--gold); }
438
437
  .bar-label { font-size: 10px; color: var(--sub-text-color); margin-top: 4px; height: 12px; }
439
438
  `;
440
439
  const cardHtml = `
@@ -449,9 +448,9 @@ var Renderer = class {
449
448
  <div class="bar-wrapper">
450
449
  <div class="bar-value">${count > 0 ? count : ""}</div>
451
450
  <div class="bar-container">
452
- <div class="bar ${count === maxCount ? "peak" : ""}" style="height: ${count / maxCount * 100}%;"></div>
451
+ <div class="bar" style="height: ${count / maxCount * 100}%;"></div>
453
452
  </div>
454
- <div class="bar-label">${hour}</div>
453
+ <div class="bar-label">${labels ? labels[hour] : hour}</div>
455
454
  </div>`).join("")}
456
455
  </div>
457
456
  </div>`;
@@ -554,7 +553,7 @@ var Stat = class {
554
553
  };
555
554
  }, "createHandler");
556
555
  if (this.config.enableCmdStat) {
557
- cmd.subcommand("cmdstat", "命令统计").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").option("separate", "-h 分离展示").option("all", "-a 全局").action(createHandler(async (scope, options) => {
556
+ cmd.subcommand("cmdstat", "命令统计").usage("查询命令统计,可指定查询范围,默认当前群组。").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").option("separate", "-h 分离展示").option("all", "-a 全局").action(createHandler(async (scope, options) => {
558
557
  const stats = await this.ctx.database.select("analyse_cmd").where({ uid: { $in: scope.uids } }).groupBy("command", { count: /* @__PURE__ */ __name((row) => import_koishi3.$.sum(row.count), "count"), lastUsed: /* @__PURE__ */ __name((row) => import_koishi3.$.max(row.timestamp), "lastUsed") }).orderBy("count", "desc").execute();
559
558
  if (stats.length === 0) return "暂无统计数据";
560
559
  let processedStats;
@@ -582,7 +581,7 @@ var Stat = class {
582
581
  }));
583
582
  }
584
583
  if (this.config.enableMsgStat) {
585
- cmd.subcommand("msgstat", "发言统计").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").option("type", "-t <type:string> 指定类型").option("all", "-a 全局").action(createHandler(async (scope, options) => {
584
+ cmd.subcommand("msgstat", "发言统计").usage("查询发言统计,可指定查询范围,默认当前群组。").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").option("type", "-t <type:string> 指定类型").option("all", "-a 全局").action(createHandler(async (scope, options) => {
586
585
  const { type } = options;
587
586
  const query = { uid: { $in: scope.uids } };
588
587
  if (type) query.type = type;
@@ -598,7 +597,7 @@ var Stat = class {
598
597
  }));
599
598
  }
600
599
  if (this.config.enableRankStat) {
601
- cmd.subcommand("rankstat", "发言排行").option("guild", "-g <guildId:string> 指定群组").option("type", "-t <type:string> 指定类型").option("hours", "-h <hours:number> 指定时长", { fallback: 24 }).option("all", "-a 全局").action(createHandler(async (scope, options) => {
600
+ cmd.subcommand("rankstat", "发言排行").usage("查询发言排行,可指定查询范围,默认当前群组。").option("guild", "-g <guildId:string> 指定群组").option("type", "-t <type:string> 指定类型").option("hours", "-h <hours:number> 指定时长", { fallback: 24 }).option("all", "-a 全局").action(createHandler(async (scope, options) => {
602
601
  const { hours, type } = options;
603
602
  const since = new Date(Date.now() - hours * import_koishi3.Time.hour);
604
603
  const query = { uid: { $in: scope.uids }, timestamp: { $gte: since } };
@@ -615,17 +614,58 @@ var Stat = class {
615
614
  }));
616
615
  }
617
616
  if (this.config.enableActivity) {
618
- cmd.subcommand("activity", "活跃统计").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").option("all", "-a 全局").action(createHandler(async (scope) => {
619
- const hourlyStats = await this.ctx.database.select("analyse_rank").where({ uid: { $in: scope.uids } }).groupBy(["timestamp"], { count: /* @__PURE__ */ __name((row) => import_koishi3.$.sum(row.count), "count") }).execute();
620
- if (hourlyStats.length === 0) return "暂无统计数据";
621
- const hourlyCounts = Array(24).fill(0);
622
- let totalMessages = 0;
623
- hourlyStats.forEach((stat) => {
624
- hourlyCounts[stat.timestamp.getHours()] += stat.count;
625
- totalMessages += stat.count;
626
- });
627
- const title = await generateTitle(this.ctx, scope.scopeDesc, { main: "活跃" });
628
- return this.renderer.renderCircadianChart({ title, time: /* @__PURE__ */ new Date(), total: totalMessages, data: hourlyCounts });
617
+ cmd.subcommand("activity", "活跃统计").usage("查询活跃统计,可指定查询范围,默认当前群组。").option("user", "-u <user:string> 指定用户").option("guild", "-g <guildId:string> 指定群组").option("hours", "-h <hours:number> 指定偏移时长").option("all", "-a 全局").option("days", "-d 切换至天数").action(createHandler(async (scope, options) => {
618
+ const { days, hours } = options;
619
+ if (days) {
620
+ const timeRangeInDays = 24;
621
+ const since = new Date(Date.now() - timeRangeInDays * import_koishi3.Time.day);
622
+ const stats = await this.ctx.database.select("analyse_rank").where({ uid: { $in: scope.uids }, timestamp: { $gte: since } }).project(["timestamp", "count"]).execute();
623
+ if (stats.length === 0) return "暂无统计数据";
624
+ const startOfToday = /* @__PURE__ */ new Date();
625
+ startOfToday.setHours(0, 0, 0, 0);
626
+ const dailyCounts = Array(timeRangeInDays).fill(0);
627
+ const dayLabels = Array(timeRangeInDays).fill("");
628
+ for (let i = 0; i < timeRangeInDays; i++) {
629
+ const d = new Date(startOfToday.getTime() - i * import_koishi3.Time.day);
630
+ dayLabels[timeRangeInDays - 1 - i] = String(d.getDate());
631
+ }
632
+ stats.forEach((stat) => {
633
+ const statDayStart = new Date(stat.timestamp);
634
+ statDayStart.setHours(0, 0, 0, 0);
635
+ const daysAgo = Math.round((startOfToday.getTime() - statDayStart.getTime()) / import_koishi3.Time.day);
636
+ if (daysAgo >= 0 && daysAgo < timeRangeInDays) {
637
+ const index = timeRangeInDays - 1 - daysAgo;
638
+ dailyCounts[index] += stat.count;
639
+ }
640
+ });
641
+ const totalMessages = dailyCounts.reduce((a, b) => a + b, 0);
642
+ const title = await generateTitle(this.ctx, scope.scopeDesc, { main: "活跃", timeRange: timeRangeInDays, timeUnit: "天" });
643
+ return this.renderer.renderCircadianChart({ title, time: /* @__PURE__ */ new Date(), total: totalMessages, data: dailyCounts, labels: dayLabels });
644
+ } else {
645
+ const timeWindowHours = 24;
646
+ const offsetHours = typeof hours === "number" ? hours : 0;
647
+ const now = /* @__PURE__ */ new Date();
648
+ const until = new Date(now.getTime() - offsetHours * import_koishi3.Time.hour);
649
+ const since = new Date(until.getTime() - timeWindowHours * import_koishi3.Time.hour);
650
+ const hourlyStats = await this.ctx.database.select("analyse_rank").where({ uid: { $in: scope.uids }, timestamp: { $gte: since, $lt: until } }).groupBy("timestamp", { count: /* @__PURE__ */ __name((row) => import_koishi3.$.sum(row.count), "count") }).execute();
651
+ if (hourlyStats.length === 0) return "暂无统计数据";
652
+ const processedCounts = Array(timeWindowHours).fill(0);
653
+ const hourLabels = Array(timeWindowHours).fill("");
654
+ for (let i = 0; i < timeWindowHours; i++) {
655
+ const d = new Date(until.getTime() - (i + 1) * import_koishi3.Time.hour);
656
+ hourLabels[timeWindowHours - 1 - i] = String(d.getHours());
657
+ }
658
+ hourlyStats.forEach((stat) => {
659
+ const hoursBeforeUntil = Math.floor((until.getTime() - stat.timestamp.getTime()) / import_koishi3.Time.hour);
660
+ if (hoursBeforeUntil >= 0 && hoursBeforeUntil < timeWindowHours) {
661
+ const index = timeWindowHours - 1 - hoursBeforeUntil;
662
+ processedCounts[index] += stat.count;
663
+ }
664
+ });
665
+ const totalMessages = processedCounts.reduce((a, b) => a + b, 0);
666
+ const title = await generateTitle(this.ctx, scope.scopeDesc, { main: "活跃", timeRange: timeWindowHours, timeUnit: "小时" });
667
+ return this.renderer.renderCircadianChart({ title, time: /* @__PURE__ */ new Date(), total: totalMessages, data: processedCounts, labels: hourLabels });
668
+ }
629
669
  }));
630
670
  }
631
671
  }
@@ -758,7 +798,7 @@ var Data = class {
758
798
  return "数据恢复失败";
759
799
  }
760
800
  });
761
- cmd.subcommand(".clear", "清除数据", { authority: 4 }).option("table", "-t <table:string> 指定表名").option("guild", "-g <guildId:string> 指定群组").option("user", "-u <user:string> 指定用户").option("days", "-d <days:number> 指定天数").option("command", "-c <command:string> 指定命令").option("all", "-a 清除全部").usage(`根据指定条件清理统计数据,可以组合多个选项以精确控制清除范围。`).action(async ({ options }) => {
801
+ cmd.subcommand(".clear", "清除数据", { authority: 4 }).usage(`清除指定统计数据,可精确控制清除范围。`).option("table", "-t <table:string> 指定表名").option("guild", "-g <guildId:string> 指定群组").option("user", "-u <user:string> 指定用户").option("days", "-d <days:number> 指定天数").option("command", "-c <command:string> 指定命令").option("all", "-a 清除全部").action(async ({ options }) => {
762
802
  if (Object.keys(options).length === 0) return "请指定清除条件";
763
803
  if (options.table && !ALL_TABLES.includes(options.table)) return `表名 ${options.table} 无效`;
764
804
  try {
@@ -831,107 +871,64 @@ ${commandOutput}`;
831
871
 
832
872
  // src/Analyse.ts
833
873
  var import_koishi6 = require("koishi");
834
- var import_basic = require("@nlpjs/basic");
835
- var import_lang_zh = require("@nlpjs/lang-zh");
874
+ var import_jieba = require("@node-rs/jieba");
875
+ var import_dict = require("@node-rs/jieba/dict");
836
876
  var Analyse = class {
837
877
  constructor(ctx, config) {
838
878
  this.ctx = ctx;
839
879
  this.config = config;
840
880
  this.renderer = new Renderer(ctx);
841
- this.nlp = new import_basic.Nlp({ languages: ["zh"], nlu: { log: false } });
842
- this.nlp.settings.autoSave = false;
843
- this.nlp.container.register("extract-lang-zh", new import_lang_zh.LangZh());
844
- this.initializeNlp().catch((err) => {
845
- this.ctx.logger.error("NLP 语言模型加载失败:", err);
846
- });
881
+ if (config.enableWordCloud) this.jieba = import_jieba.Jieba.withDict(import_dict.dict);
847
882
  }
848
883
  static {
849
884
  __name(this, "Analyse");
850
885
  }
851
886
  renderer;
852
- nlp;
853
- isNlpReady = false;
887
+ jieba = null;
854
888
  /**
855
- * @private
856
- * @method initializeNlp
857
- * @description 异步加载并训练 NLP 模型。
889
+ * @public @method registerCommands
890
+ * @description 在主命令下注册子命令。
891
+ * @param cmd - 主命令实例。
858
892
  */
859
- async initializeNlp() {
860
- await this.nlp.train();
861
- this.isNlpReady = true;
862
- }
863
893
  registerCommands(cmd) {
864
894
  if (this.config.enableWordCloud) {
865
- cmd.subcommand(".wordcloud", "生成词云").usage("基于指定范围内的聊天记录生成词云图。").option("guild", "-g <guildId:string> 指定群组").option("user", "-u <user:string> 指定用户").option("all", "-a 全局").option("hours", "-h <hours:number> 指定时长", { fallback: 24 }).action(async ({ session, options }) => {
866
- if (!this.isNlpReady) return "文本分析尚未就绪,请稍后再试";
895
+ cmd.subcommand("wordcloud", "生成词云").usage("基于聊天记录生成词云图,可指定范围,默认当前群组。").option("guild", "-g <guildId:string> 指定群组").option("user", "-u <user:string> 指定用户").option("hours", "-h <hours:number> 指定时长", { fallback: 24 }).option("all", "-a 全局").action(async ({ session, options }) => {
896
+ if (!this.jieba) return "Jieba 分词服务未就绪";
867
897
  const scope = await parseQueryScope(this.ctx, session, options);
868
898
  if (scope.error) return scope.error;
899
+ scope.uids ??= (await this.ctx.database.get("analyse_user", {}, ["uid"])).map((u) => u.uid);
900
+ if (!scope.uids?.length) return "暂无用户数据";
869
901
  const since = new Date(Date.now() - options.hours * import_koishi6.Time.hour);
870
- const records = await this.ctx.database.select("analyse_cache").where({ uid: { $in: scope.uids }, timestamp: { $gte: since } }).project(["content"]).execute();
871
- if (records.length === 0) return "暂无统计数据";
902
+ const records = await this.ctx.database.get("analyse_cache", { uid: { $in: scope.uids }, timestamp: { $gte: since } }, ["content"]);
903
+ if (!records.length) return "暂无统计数据";
872
904
  const allText = records.map((r) => r.content).join(" ");
873
- const result = await this.nlp.process("zh", allText);
874
- const words = (result.stems || []).filter((stem) => stem.length > 1);
875
- const wordCounts = words.reduce((map, word) => {
876
- map.set(word, (map.get(word) || 0) + 1);
877
- return map;
878
- }, /* @__PURE__ */ new Map());
879
- if (wordCounts.size === 0) return "暂无有效词语";
905
+ const exclusionSet = /* @__PURE__ */ new Set([
906
+ "[face]",
907
+ "[file]",
908
+ "[forward]",
909
+ "[img]",
910
+ "[audio]",
911
+ "[video]",
912
+ "[json]",
913
+ "[rps]",
914
+ "[markdown]",
915
+ "[dice]"
916
+ ]);
917
+ const words = this.jieba.cut(allText).filter((w) => {
918
+ if (w.length <= 1) return false;
919
+ if (/^\d+$/.test(w)) return false;
920
+ if (exclusionSet.has(w)) return false;
921
+ if (/^\[at:.*?\]$/.test(w)) return false;
922
+ return true;
923
+ });
924
+ if (!words.length) return "暂无有效词语";
925
+ const wordCounts = words.reduce((map, word) => map.set(word, (map.get(word) || 0) + 1), /* @__PURE__ */ new Map());
880
926
  const wordList = Array.from(wordCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 150);
881
927
  const title = await generateTitle(this.ctx, scope.scopeDesc, { main: "词云" });
882
- const renderResult = await this.renderer.renderWordCloud({ title, time: /* @__PURE__ */ new Date(), words: wordList });
883
- if (typeof renderResult === "string") return renderResult;
884
- if (Array.isArray(renderResult) && renderResult.length > 0) {
885
- for (const buffer of renderResult) await session.sendQueued(import_koishi6.h.image(buffer, "image/png"));
886
- }
887
- });
888
- }
889
- if (this.config.enableVocabulary) {
890
- cmd.subcommand(".vocabulary", "词汇排行").usage("根据不重复词汇量占总词汇量的比例进行排行。").option("guild", "-g <guildId:string> 指定群组").option("all", "-a 全局").option("hours", "-h <hours:number> 指定时长", { fallback: 24 }).action(async ({ session, options }) => {
891
- if (!this.isNlpReady) return "文本分析尚未就绪,请稍后再试";
892
- const scope = await parseQueryScope(this.ctx, session, options);
893
- if (scope.error) return scope.error;
894
- const users = await this.ctx.database.get("analyse_user", { uid: { $in: scope.uids } }, ["uid", "userName"]);
895
- const userNameMap = new Map(users.map((u) => [u.uid, u.userName]));
896
- const since = new Date(Date.now() - options.hours * import_koishi6.Time.hour);
897
- const allRecords = await this.ctx.database.get("analyse_cache", { uid: { $in: scope.uids }, timestamp: { $gte: since } }, ["uid", "content"]);
898
- if (allRecords.length === 0) return "暂无统计数据";
899
- const messagesByUid = /* @__PURE__ */ new Map();
900
- for (const record of allRecords) {
901
- if (!messagesByUid.has(record.uid)) messagesByUid.set(record.uid, []);
902
- messagesByUid.get(record.uid).push(record.content);
903
- }
904
- const richnessData = [];
905
- for (const [uid, messages] of messagesByUid.entries()) {
906
- const allText = messages.join(" ");
907
- const result = await this.nlp.process("zh", allText);
908
- const words = (result.stems || []).filter((stem) => stem.length > 1);
909
- if (words.length < 50) continue;
910
- const uniqueWords = new Set(words);
911
- const richness = uniqueWords.size / words.length;
912
- richnessData.push({
913
- name: userNameMap.get(uid) || `UID ${uid}`,
914
- total: words.length,
915
- unique: uniqueWords.size,
916
- richness
917
- });
918
- }
919
- if (richnessData.length === 0) return "暂无有效词语";
920
- richnessData.sort((a, b) => b.richness - a.richness);
921
- const list = richnessData.map((item) => [
922
- item.name,
923
- item.unique,
924
- item.total,
925
- `${(item.richness * 100).toFixed(2)}%`
926
- ]);
927
- const title = await generateTitle(this.ctx, scope.scopeDesc, { main: "词汇排行" });
928
- const renderResult = await this.renderer.renderList(
929
- { title, time: /* @__PURE__ */ new Date(), total: richnessData.length, list },
930
- ["用户", "不重复词数", "总词数", "丰富度"]
931
- );
932
- if (typeof renderResult === "string") return renderResult;
933
- if (Array.isArray(renderResult) && renderResult.length > 0) {
934
- for (const buffer of renderResult) await session.sendQueued(import_koishi6.h.image(buffer, "image/png"));
928
+ const result = await this.renderer.renderWordCloud({ title, time: /* @__PURE__ */ new Date(), words: wordList });
929
+ if (typeof result === "string") return result;
930
+ if (Array.isArray(result) && result.length > 0) {
931
+ for (const buffer of result) await session.sendQueued(import_koishi6.h.image(buffer, "image/png"));
935
932
  }
936
933
  });
937
934
  }
@@ -969,8 +966,7 @@ var Config3 = import_koishi7.Schema.intersect([
969
966
  }).description("基础分析配置"),
970
967
  import_koishi7.Schema.object({
971
968
  enableOriRecord: import_koishi7.Schema.boolean().default(true).description("启用原始记录"),
972
- enableWordCloud: import_koishi7.Schema.boolean().default(true).description("启用词云生成"),
973
- enableVocabulary: import_koishi7.Schema.boolean().default(true).description("启用词汇排行")
969
+ enableWordCloud: import_koishi7.Schema.boolean().default(true).description("启用词云生成")
974
970
  }).description("高级分析配置")
975
971
  ]);
976
972
  async function parseQueryScope(ctx, session, options) {
@@ -997,16 +993,18 @@ async function generateTitle(ctx, scopeDesc, options) {
997
993
  const [user] = await ctx.database.get("analyse_user", { userId: scopeDesc.userId }, ["userName"]);
998
994
  userName = user?.userName || scopeDesc.userId;
999
995
  }
996
+ const timeText = options.timeRange ? `${options.timeRange}${options.timeUnit || "小时"}` : "";
1000
997
  const typeText = options.subtype ? `“${options.subtype}”` : "";
1001
998
  const mainText = options.main;
1002
- if (mainText.includes("排行")) {
999
+ if (mainText.includes("排行") || mainText.includes("活跃")) {
1003
1000
  scopeText = guildName || "全局";
1004
- return `${options.timeRange}小时${scopeText}${typeText}${mainText}`;
1001
+ } else {
1002
+ if (userName && guildName) scopeText = `${guildName} ${userName}`;
1003
+ else if (userName) scopeText = userName;
1004
+ else if (guildName) scopeText = guildName;
1005
1005
  }
1006
- if (userName && guildName) scopeText = `${guildName} ${userName}`;
1007
- else if (userName) scopeText = userName;
1008
- else if (guildName) scopeText = guildName;
1009
- return `${scopeText}${typeText}${mainText}统计`;
1006
+ const suffix = mainText.includes("排行") ? "" : "统计";
1007
+ return `${timeText}${scopeText}${typeText}${mainText}${suffix}`;
1010
1008
  }
1011
1009
  __name(generateTitle, "generateTitle");
1012
1010
  function apply(ctx, config) {
@@ -1015,7 +1013,7 @@ function apply(ctx, config) {
1015
1013
  new Stat(ctx, config).registerCommands(analyse);
1016
1014
  if (config.enableWhoAt) new WhoAt(ctx, config).registerCommand(analyse);
1017
1015
  if (config.enableDataIO) new Data(ctx).registerCommands(analyse);
1018
- if (config.enableOriRecord && (config.enableWordCloud || config.enableVocabulary)) new Analyse(ctx, config).registerCommands(analyse);
1016
+ if (config.enableOriRecord && config.enableWordCloud) new Analyse(ctx, config).registerCommands(analyse);
1019
1017
  }
1020
1018
  __name(apply, "apply");
1021
1019
  // Annotate the CommonJS export names for ESM import in node:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-chat-analyse",
3
3
  "description": "聊天记录分析",
4
- "version": "0.6.3",
4
+ "version": "0.7.0",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],
@@ -39,7 +39,6 @@
39
39
  "koishi": "4.18.8"
40
40
  },
41
41
  "dependencies": {
42
- "@nlpjs/basic": "^4.26.1",
43
- "@nlpjs/lang-zh": "^4.26.1"
42
+ "@node-rs/jieba": "^2.0.1"
44
43
  }
45
44
  }