@zhin.js/plugin-group-suite 1.1.14 → 1.1.16
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/README.md +12 -0
- package/commands/checkin/index.js +3 -3
- package/commands/checkin/index.ts +3 -3
- package/commands/forget/index.js +3 -3
- package/commands/forget/index.ts +3 -3
- package/commands/keyword-add/[keyword]/index.js +4 -3
- package/commands/keyword-add/[keyword]/index.ts +4 -3
- package/commands/keyword-list/index.js +4 -3
- package/commands/keyword-list/index.ts +4 -3
- package/commands/keyword-remove/[keyword]/index.js +5 -4
- package/commands/keyword-remove/[keyword]/index.ts +5 -4
- package/commands/mypoints/index.js +3 -3
- package/commands/mypoints/index.ts +3 -3
- package/commands/mystats/index.js +3 -3
- package/commands/mystats/index.ts +3 -3
- package/commands/rank/index.js +3 -3
- package/commands/rank/index.ts +3 -3
- package/commands/stats/index.js +6 -5
- package/commands/stats/index.ts +6 -5
- package/commands/stats-card/index.js +4 -3
- package/commands/stats-card/index.ts +4 -3
- package/commands/stats-rank/index.js +6 -5
- package/commands/stats-rank/index.ts +6 -5
- package/commands/stats-week/index.js +6 -5
- package/commands/stats-week/index.ts +6 -5
- package/commands/teach/index.js +3 -3
- package/commands/teach/index.ts +3 -3
- package/commands/teach-list/[[page]]/index.js +3 -3
- package/commands/teach-list/[[page]]/index.ts +3 -3
- package/commands/teach-regex/index.js +3 -3
- package/commands/teach-regex/index.ts +3 -3
- package/handlers/welcome/index.js +9 -1
- package/handlers/welcome/index.ts +8 -1
- package/lib/analysis-card.d.ts +1 -1
- package/lib/analysis-card.d.ts.map +1 -1
- package/lib/analysis-card.js +12 -11
- package/lib/analysis-card.js.map +1 -1
- package/lib/analysis.d.ts +2 -2
- package/lib/analysis.d.ts.map +1 -1
- package/lib/analysis.js +14 -20
- package/lib/analysis.js.map +1 -1
- package/lib/checkin-lib.d.ts +1 -1
- package/lib/checkin-lib.d.ts.map +1 -1
- package/lib/checkin-lib.js +23 -22
- package/lib/checkin-lib.js.map +1 -1
- package/lib/conversation-scope.d.ts +1 -0
- package/lib/conversation-scope.d.ts.map +1 -1
- package/lib/conversation-scope.js.map +1 -1
- package/lib/i18n.d.ts +2 -0
- package/lib/i18n.d.ts.map +1 -0
- package/lib/i18n.js +480 -0
- package/lib/i18n.js.map +1 -0
- package/lib/keywords.d.ts +1 -0
- package/lib/keywords.d.ts.map +1 -1
- package/lib/keywords.js +8 -7
- package/lib/keywords.js.map +1 -1
- package/lib/shared-runtime.d.ts +1 -0
- package/lib/shared-runtime.d.ts.map +1 -1
- package/lib/shared-runtime.js +2 -1
- package/lib/shared-runtime.js.map +1 -1
- package/lib/stats-card.d.ts +2 -2
- package/lib/stats-card.d.ts.map +1 -1
- package/lib/stats-card.js +15 -14
- package/lib/stats-card.js.map +1 -1
- package/lib/stats-data.d.ts +3 -2
- package/lib/stats-data.d.ts.map +1 -1
- package/lib/stats-data.js +13 -12
- package/lib/stats-data.js.map +1 -1
- package/lib/stats-lib.d.ts.map +1 -1
- package/lib/stats-lib.js +8 -7
- package/lib/stats-lib.js.map +1 -1
- package/lib/teach-lib.d.ts +1 -1
- package/lib/teach-lib.d.ts.map +1 -1
- package/lib/teach-lib.js +27 -26
- package/lib/teach-lib.js.map +1 -1
- package/package.json +12 -12
- package/skills/checkin/tools/checkin_query/index.js +5 -4
- package/skills/checkin/tools/checkin_query/index.ts +5 -4
- package/skills/checkin/tools/checkin_rank/index.js +4 -3
- package/skills/checkin/tools/checkin_rank/index.ts +4 -3
- package/skills/group-daily-analysis/tools/group_announce/index.js +3 -2
- package/skills/group-daily-analysis/tools/group_announce/index.ts +3 -2
- package/skills/group-daily-analysis/tools/stats_query/index.js +4 -3
- package/skills/group-daily-analysis/tools/stats_query/index.ts +4 -3
- package/skills/group-daily-analysis/tools/stats_user/index.js +4 -3
- package/skills/group-daily-analysis/tools/stats_user/index.ts +4 -3
- package/src/analysis-card.ts +13 -11
- package/src/analysis.ts +15 -13
- package/src/checkin-lib.ts +23 -21
- package/src/conversation-scope.ts +1 -0
- package/src/i18n.ts +480 -0
- package/src/keywords.ts +9 -7
- package/src/shared-runtime.ts +3 -1
- package/src/stats-card.ts +17 -16
- package/src/stats-data.ts +14 -12
- package/src/stats-lib.ts +8 -7
- package/src/teach-lib.ts +27 -26
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from '../../../../src/i18n.js';
|
|
1
2
|
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { getCheckinModel } from '../../../../src/db-store.js';
|
|
@@ -18,7 +19,7 @@ export default defineAgentTool<{ user_id?: string; group_id?: string }>({
|
|
|
18
19
|
async execute({ user_id: userId, group_id: requestedGroupId }, context) {
|
|
19
20
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
20
21
|
const model = getCheckinModel(runtime.db);
|
|
21
|
-
if (!model) return '
|
|
22
|
+
if (!model) return t(context.locale, 'checkinDb');
|
|
22
23
|
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
23
24
|
const query = {
|
|
24
25
|
...(userId ? { user_id: userId } : {}),
|
|
@@ -26,12 +27,12 @@ export default defineAgentTool<{ user_id?: string; group_id?: string }>({
|
|
|
26
27
|
};
|
|
27
28
|
const rows = await model.select().where(query);
|
|
28
29
|
if (userId) {
|
|
29
|
-
if (rows.length === 0) return
|
|
30
|
+
if (rows.length === 0) return t(context.locale, 'userCheckinEmpty', { user: userId });
|
|
30
31
|
const user = rows[0]!;
|
|
31
|
-
return
|
|
32
|
+
return t(context.locale, 'userCheckinInfo', { name: String(user.user_name ?? userId), points: Number(user.points ?? 0), total: Number(user.total_checkins ?? 0), streak: Number(user.streak ?? 0), max: Number(user.max_streak ?? 0), last: String(user.last_checkin ?? '') });
|
|
32
33
|
}
|
|
33
34
|
const totalPoints = rows.reduce((sum, user) => sum + Number(user.points ?? 0), 0);
|
|
34
35
|
const todayCount = rows.filter((user) => user.last_checkin === todayStr()).length;
|
|
35
|
-
return
|
|
36
|
+
return t(context.locale, 'checkinOverview', { users: rows.length, points: totalPoints, today: todayCount });
|
|
36
37
|
},
|
|
37
38
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../lib/i18n.js";
|
|
2
3
|
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { getCheckinModel } from "../../../../lib/db-store.js";
|
|
@@ -17,7 +18,7 @@ export default defineAgentTool({
|
|
|
17
18
|
async execute({ limit, group_id: requestedGroupId }, context) {
|
|
18
19
|
const model = getCheckinModel(context.use(groupSuiteRuntimeToken).db);
|
|
19
20
|
if (!model)
|
|
20
|
-
return '
|
|
21
|
+
return t(context.locale, 'checkinDb');
|
|
21
22
|
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
22
23
|
const rows = await model.select().where({ context_type: 'group', context_id: groupId });
|
|
23
24
|
const count = Math.min(Math.max(Number(limit) || 10, 1), 50);
|
|
@@ -25,7 +26,7 @@ export default defineAgentTool({
|
|
|
25
26
|
.sort((left, right) => Number(right.points ?? 0) - Number(left.points ?? 0))
|
|
26
27
|
.slice(0, count);
|
|
27
28
|
if (ranked.length === 0)
|
|
28
|
-
return '
|
|
29
|
-
return ranked.map((user, index) =>
|
|
29
|
+
return t(context.locale, 'rankEmpty');
|
|
30
|
+
return ranked.map((user, index) => t(context.locale, 'pointsToolRow', { rank: index + 1, name: String(user.user_name ?? user.user_id), points: Number(user.points ?? 0), days: Number(user.streak ?? 0) })).join('\n');
|
|
30
31
|
},
|
|
31
32
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from '../../../../src/i18n.js';
|
|
1
2
|
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { getCheckinModel } from '../../../../src/db-store.js';
|
|
@@ -16,16 +17,16 @@ export default defineAgentTool<{ limit?: number; group_id?: string }>({
|
|
|
16
17
|
scopes: ['group'],
|
|
17
18
|
async execute({ limit, group_id: requestedGroupId }, context) {
|
|
18
19
|
const model = getCheckinModel(context.use(groupSuiteRuntimeToken).db);
|
|
19
|
-
if (!model) return '
|
|
20
|
+
if (!model) return t(context.locale, 'checkinDb');
|
|
20
21
|
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
21
22
|
const rows = await model.select().where({ context_type: 'group', context_id: groupId });
|
|
22
23
|
const count = Math.min(Math.max(Number(limit) || 10, 1), 50);
|
|
23
24
|
const ranked = [...rows]
|
|
24
25
|
.sort((left, right) => Number(right.points ?? 0) - Number(left.points ?? 0))
|
|
25
26
|
.slice(0, count);
|
|
26
|
-
if (ranked.length === 0) return '
|
|
27
|
+
if (ranked.length === 0) return t(context.locale, 'rankEmpty');
|
|
27
28
|
return ranked.map((user, index) =>
|
|
28
|
-
|
|
29
|
+
t(context.locale, 'pointsToolRow', { rank: index + 1, name: String(user.user_name ?? user.user_id), points: Number(user.points ?? 0), days: Number(user.streak ?? 0) }),
|
|
29
30
|
).join('\n');
|
|
30
31
|
},
|
|
31
32
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../lib/i18n.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
export default defineAgentTool({
|
|
4
5
|
description: '生成群聊公告或通知消息',
|
|
@@ -8,7 +9,7 @@ export default defineAgentTool({
|
|
|
8
9
|
required: ['message'],
|
|
9
10
|
},
|
|
10
11
|
requiresApproval: 'never',
|
|
11
|
-
execute({ message }) {
|
|
12
|
-
return
|
|
12
|
+
execute({ message }, context) {
|
|
13
|
+
return t(context.locale, 'announcement', { message });
|
|
13
14
|
},
|
|
14
15
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from '../../../../src/i18n.js';
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
|
|
3
4
|
export default defineAgentTool<{ message: string }>({
|
|
@@ -8,7 +9,7 @@ export default defineAgentTool<{ message: string }>({
|
|
|
8
9
|
required: ['message'],
|
|
9
10
|
},
|
|
10
11
|
requiresApproval: 'never',
|
|
11
|
-
execute({ message }) {
|
|
12
|
-
return
|
|
12
|
+
execute({ message }, context) {
|
|
13
|
+
return t(context.locale, 'announcement', { message });
|
|
13
14
|
},
|
|
14
15
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../lib/i18n.js";
|
|
2
3
|
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { groupSuiteRuntimeToken } from "../../../../lib/runtime-state.js";
|
|
@@ -24,11 +25,11 @@ export default defineAgentTool({
|
|
|
24
25
|
: period === 'month' ? monthStartStr() : todayStr();
|
|
25
26
|
const stats = await queryStats(groupId, fromDate, runtime);
|
|
26
27
|
if (stats.size === 0)
|
|
27
|
-
return
|
|
28
|
+
return t(context.locale, 'periodStatsEmpty', { period });
|
|
28
29
|
const ranked = [...stats.values()].sort((left, right) => right.count - left.count);
|
|
29
30
|
const total = ranked.reduce((sum, item) => sum + item.count, 0);
|
|
30
31
|
const lines = ranked.slice(0, 10)
|
|
31
|
-
.map((item, index) => `${index + 1}
|
|
32
|
-
return
|
|
32
|
+
.map((item, index) => t(context.locale, 'statsRow', { prefix: `${index + 1}.`, name: item.name, count: item.count }));
|
|
33
|
+
return t(context.locale, 'statsOverview', { period, total, users: stats.size, lines: lines.join('\n') });
|
|
33
34
|
},
|
|
34
35
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from '../../../../src/i18n.js';
|
|
1
2
|
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { groupSuiteRuntimeToken } from '../../../../src/runtime-state.js';
|
|
@@ -25,11 +26,11 @@ export default defineAgentTool<{ group_id?: string; period?: Period }>({
|
|
|
25
26
|
? weekStartStr()
|
|
26
27
|
: period === 'month' ? monthStartStr() : todayStr();
|
|
27
28
|
const stats = await queryStats(groupId, fromDate, runtime);
|
|
28
|
-
if (stats.size === 0) return
|
|
29
|
+
if (stats.size === 0) return t(context.locale, 'periodStatsEmpty', { period });
|
|
29
30
|
const ranked = [...stats.values()].sort((left, right) => right.count - left.count);
|
|
30
31
|
const total = ranked.reduce((sum, item) => sum + item.count, 0);
|
|
31
32
|
const lines = ranked.slice(0, 10)
|
|
32
|
-
.map((item, index) => `${index + 1}
|
|
33
|
-
return
|
|
33
|
+
.map((item, index) => t(context.locale, 'statsRow', { prefix: `${index + 1}.`, name: item.name, count: item.count }));
|
|
34
|
+
return t(context.locale, 'statsOverview', { period, total, users: stats.size, lines: lines.join('\n') });
|
|
34
35
|
},
|
|
35
36
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { messages as t } from "../../../../lib/i18n.js";
|
|
2
3
|
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { getStatsModel } from "../../../../lib/db-store.js";
|
|
@@ -22,14 +23,14 @@ export default defineAgentTool({
|
|
|
22
23
|
await flushStatsBuffer(runtime);
|
|
23
24
|
const model = getStatsModel(runtime.db);
|
|
24
25
|
if (!model)
|
|
25
|
-
return '
|
|
26
|
+
return t(context.locale, 'statsDb');
|
|
26
27
|
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
27
28
|
const rows = await model.select().where({
|
|
28
29
|
user_id: userId,
|
|
29
30
|
group_id: groupId,
|
|
30
31
|
});
|
|
31
32
|
if (rows.length === 0)
|
|
32
|
-
return
|
|
33
|
+
return t(context.locale, 'userStatsEmpty', { user: userId });
|
|
33
34
|
const today = todayStr();
|
|
34
35
|
const weekStart = weekStartStr();
|
|
35
36
|
let todayCount = 0;
|
|
@@ -44,6 +45,6 @@ export default defineAgentTool({
|
|
|
44
45
|
todayCount += count;
|
|
45
46
|
}
|
|
46
47
|
const name = String(rows[0].user_name ?? userId);
|
|
47
|
-
return
|
|
48
|
+
return t(context.locale, 'userStatsInfo', { name, today: todayCount, week: weekCount, total: totalCount, days: rows.length });
|
|
48
49
|
},
|
|
49
50
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from '../../../../src/i18n.js';
|
|
1
2
|
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { getStatsModel } from '../../../../src/db-store.js';
|
|
@@ -21,13 +22,13 @@ export default defineAgentTool<{ user_id: string; group_id?: string }>({
|
|
|
21
22
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
22
23
|
await flushStatsBuffer(runtime);
|
|
23
24
|
const model = getStatsModel(runtime.db);
|
|
24
|
-
if (!model) return '
|
|
25
|
+
if (!model) return t(context.locale, 'statsDb');
|
|
25
26
|
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
26
27
|
const rows = await model.select().where({
|
|
27
28
|
user_id: userId,
|
|
28
29
|
group_id: groupId,
|
|
29
30
|
});
|
|
30
|
-
if (rows.length === 0) return
|
|
31
|
+
if (rows.length === 0) return t(context.locale, 'userStatsEmpty', { user: userId });
|
|
31
32
|
const today = todayStr();
|
|
32
33
|
const weekStart = weekStartStr();
|
|
33
34
|
let todayCount = 0;
|
|
@@ -40,6 +41,6 @@ export default defineAgentTool<{ user_id: string; group_id?: string }>({
|
|
|
40
41
|
if (row.date === today) todayCount += count;
|
|
41
42
|
}
|
|
42
43
|
const name = String(rows[0]!.user_name ?? userId);
|
|
43
|
-
return
|
|
44
|
+
return t(context.locale, 'userStatsInfo', { name, today: todayCount, week: weekCount, total: totalCount, days: rows.length });
|
|
44
45
|
},
|
|
45
46
|
});
|
package/src/analysis-card.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from './i18n.js';
|
|
1
2
|
import { jsx, renderToHtml } from "@zhin.js/jsx";
|
|
2
3
|
import {
|
|
3
4
|
BarChart,
|
|
@@ -28,10 +29,11 @@ const T = {
|
|
|
28
29
|
} as const;
|
|
29
30
|
|
|
30
31
|
export async function buildAnalysisReportHtml(
|
|
31
|
-
data: AnalysisReportData
|
|
32
|
+
data: AnalysisReportData,
|
|
33
|
+
locale?: import('zhin.js/i18n').Locale
|
|
32
34
|
): Promise<string> {
|
|
33
35
|
const { stats, channelName, days, startDate, endDate, llm } = data;
|
|
34
|
-
const title = channelName ?
|
|
36
|
+
const title = channelName ? t(locale, 'analysisNamed', { name: channelName }) : t(locale, 'analysis');
|
|
35
37
|
const peakLabel = `${String(stats.mostActiveHour).padStart(2, "0")}:00`;
|
|
36
38
|
const hourlyValues = Array.from(
|
|
37
39
|
{ length: 24 },
|
|
@@ -41,7 +43,7 @@ export async function buildAnalysisReportHtml(
|
|
|
41
43
|
const llmBlocks = [
|
|
42
44
|
llm?.topics?.length
|
|
43
45
|
? jsx(Section, {
|
|
44
|
-
title:
|
|
46
|
+
title: t(locale, 'topics'),
|
|
45
47
|
children: llm.topics.map((topic, i) =>
|
|
46
48
|
jsx(TopicItem, {
|
|
47
49
|
index: i + 1,
|
|
@@ -53,7 +55,7 @@ export async function buildAnalysisReportHtml(
|
|
|
53
55
|
: "",
|
|
54
56
|
llm?.quotes?.length
|
|
55
57
|
? jsx(Section, {
|
|
56
|
-
title:
|
|
58
|
+
title: t(locale, 'quotes'),
|
|
57
59
|
children: llm.quotes.map((quote, i) =>
|
|
58
60
|
jsx(QuoteCard, {
|
|
59
61
|
index: i + 1,
|
|
@@ -66,7 +68,7 @@ export async function buildAnalysisReportHtml(
|
|
|
66
68
|
: "",
|
|
67
69
|
llm?.userTitles?.length
|
|
68
70
|
? jsx(Section, {
|
|
69
|
-
title:
|
|
71
|
+
title: t(locale, 'profiles'),
|
|
70
72
|
children: llm.userTitles.map((user, i) =>
|
|
71
73
|
jsx(ProfileRow, {
|
|
72
74
|
index: i + 1,
|
|
@@ -82,27 +84,27 @@ export async function buildAnalysisReportHtml(
|
|
|
82
84
|
const body = elevatedCard([
|
|
83
85
|
jsx(CardHeader, {
|
|
84
86
|
title,
|
|
85
|
-
subtitle:
|
|
87
|
+
subtitle: t(locale, 'analysisRange', { start: startDate, end: endDate, days }),
|
|
86
88
|
}),
|
|
87
89
|
jsx(Row, {
|
|
88
90
|
children: [
|
|
89
91
|
jsx(StatChip, {
|
|
90
|
-
label:
|
|
92
|
+
label: t(locale, 'messages'),
|
|
91
93
|
value: formatCount(stats.messageCount),
|
|
92
94
|
accent: T.accentMsg,
|
|
93
95
|
}),
|
|
94
96
|
jsx(StatChip, {
|
|
95
|
-
label:
|
|
97
|
+
label: t(locale, 'participants'),
|
|
96
98
|
value: formatCount(stats.participantCount),
|
|
97
99
|
accent: T.accentPeople,
|
|
98
100
|
}),
|
|
99
101
|
jsx(StatChip, {
|
|
100
|
-
label:
|
|
102
|
+
label: t(locale, 'characters'),
|
|
101
103
|
value: formatCount(stats.totalChars),
|
|
102
104
|
accent: T.accentChars,
|
|
103
105
|
}),
|
|
104
106
|
jsx(StatChip, {
|
|
105
|
-
label:
|
|
107
|
+
label: t(locale, 'active'),
|
|
106
108
|
value: peakLabel,
|
|
107
109
|
accent: T.accentHour,
|
|
108
110
|
}),
|
|
@@ -111,7 +113,7 @@ export async function buildAnalysisReportHtml(
|
|
|
111
113
|
style: "margin-bottom:4px",
|
|
112
114
|
}),
|
|
113
115
|
jsx(Section, {
|
|
114
|
-
title:
|
|
116
|
+
title: t(locale, 'hourDistribution'),
|
|
115
117
|
children: jsx(BarChart, {
|
|
116
118
|
values: hourlyValues,
|
|
117
119
|
peakIndex: stats.mostActiveHour,
|
package/src/analysis.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from './i18n.js';
|
|
1
2
|
/**
|
|
2
3
|
* 群日常分析:从收件箱查询、基础统计、文本报告。
|
|
3
4
|
* 数据源为 zhin 内置 unified_inbox_message 表(需 inbox.enabled)。
|
|
@@ -155,21 +156,22 @@ export function computeBasicStats(rows: InboxMessageRow[]): BasicStats {
|
|
|
155
156
|
*/
|
|
156
157
|
export function formatTextReport(
|
|
157
158
|
stats: BasicStats,
|
|
158
|
-
options: { channelName?: string; days: number; startDate: string; endDate: string }
|
|
159
|
+
options: { channelName?: string; days: number; startDate: string; endDate: string },
|
|
160
|
+
locale?: import('zhin.js/i18n').Locale
|
|
159
161
|
): string {
|
|
160
162
|
const lines: string[] = [];
|
|
161
163
|
const title = options.channelName
|
|
162
|
-
?
|
|
163
|
-
:
|
|
164
|
+
? t(locale, 'analysisTextNamed', { name: options.channelName })
|
|
165
|
+
: t(locale, 'analysis');
|
|
164
166
|
lines.push(`📊 ${title}`);
|
|
165
|
-
lines.push(
|
|
167
|
+
lines.push(t(locale, 'analysisTextRange', { start: options.startDate, end: options.endDate, days: options.days }));
|
|
166
168
|
lines.push("");
|
|
167
|
-
lines.push(
|
|
168
|
-
lines.push(
|
|
169
|
-
lines.push(
|
|
170
|
-
lines.push(
|
|
169
|
+
lines.push(t(locale, 'analysisMessages', { count: stats.messageCount }));
|
|
170
|
+
lines.push(t(locale, 'analysisPeople', { count: stats.participantCount }));
|
|
171
|
+
lines.push(t(locale, 'analysisChars', { count: stats.totalChars }));
|
|
172
|
+
lines.push(t(locale, 'analysisPeak', { start: stats.mostActiveHour, end: stats.mostActiveHour + 1 }));
|
|
171
173
|
lines.push("");
|
|
172
|
-
lines.push(
|
|
174
|
+
lines.push(t(locale, 'hourDistributionText'));
|
|
173
175
|
const maxH = Math.max(...Object.values(stats.hourlyDistribution), 1);
|
|
174
176
|
for (let h = 0; h < 24; h++) {
|
|
175
177
|
const c = stats.hourlyDistribution[h] || 0;
|
|
@@ -183,24 +185,24 @@ export function formatTextReport(
|
|
|
183
185
|
* 将 LLM 分析结果追加到文本报告。
|
|
184
186
|
* 话题/金句/用户画像 设计灵感来自 astrbot_plugin_qq_group_daily_analysis
|
|
185
187
|
*/
|
|
186
|
-
export function appendLLMReport(textReport: string, llm: LLMAnalysis): string {
|
|
188
|
+
export function appendLLMReport(textReport: string, llm: LLMAnalysis, locale?: import('zhin.js/i18n').Locale): string {
|
|
187
189
|
const lines: string[] = [textReport, ""];
|
|
188
190
|
if (llm.topics?.length) {
|
|
189
|
-
lines.push(
|
|
191
|
+
lines.push(t(locale, 'llmTopics'));
|
|
190
192
|
llm.topics.forEach((t, i) => {
|
|
191
193
|
lines.push(` ${i + 1}. ${t.topic}${t.summary ? ` — ${t.summary}` : ""}`);
|
|
192
194
|
});
|
|
193
195
|
lines.push("");
|
|
194
196
|
}
|
|
195
197
|
if (llm.quotes?.length) {
|
|
196
|
-
lines.push(
|
|
198
|
+
lines.push(t(locale, 'llmQuotes'));
|
|
197
199
|
llm.quotes.forEach((q, i) => {
|
|
198
200
|
lines.push(` ${i + 1}. 「${q.content}」 — ${q.sender}(${q.reason})`);
|
|
199
201
|
});
|
|
200
202
|
lines.push("");
|
|
201
203
|
}
|
|
202
204
|
if (llm.userTitles?.length) {
|
|
203
|
-
lines.push(
|
|
205
|
+
lines.push(t(locale, 'llmProfiles'));
|
|
204
206
|
llm.userTitles.forEach((u, i) => {
|
|
205
207
|
lines.push(` ${i + 1}. ${u.name} — ${u.title}${u.reason ? `(${u.reason})` : ""}`);
|
|
206
208
|
});
|
package/src/checkin-lib.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from './i18n.js';
|
|
1
2
|
import type { ConversationInput } from './conversation-scope.js';
|
|
2
3
|
import type { GroupSuiteConfig } from './config.js';
|
|
3
4
|
import { getCheckinModel } from './db-store.js';
|
|
@@ -70,19 +71,19 @@ export async function doCheckin(
|
|
|
70
71
|
runtime: GroupSuiteRuntime,
|
|
71
72
|
): Promise<string> {
|
|
72
73
|
const M = getCheckinModel(runtime.db);
|
|
73
|
-
if (!M) return '
|
|
74
|
+
if (!M) return t(input.locale, 'checkinRetry');
|
|
74
75
|
|
|
75
76
|
const { id: userId, name: userName } = resolveSender(input);
|
|
76
|
-
if (!userId) return '
|
|
77
|
+
if (!userId) return t(input.locale, 'senderMissing');
|
|
77
78
|
|
|
78
79
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
79
80
|
return serializedCheckin(runtime.checkinChains, `${userId}:${ctxType}:${ctxId}`, async () => {
|
|
80
81
|
const user = await getOrCreateUser(M, userId, userName, ctxType, ctxId);
|
|
81
|
-
if (!user) return '
|
|
82
|
+
if (!user) return t(input.locale, 'checkinFailed');
|
|
82
83
|
|
|
83
84
|
const today = todayStr();
|
|
84
85
|
if (user.last_checkin === today) {
|
|
85
|
-
return
|
|
86
|
+
return t(input.locale, 'alreadyChecked', { points: String(user.points), days: String(user.streak) });
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
const isConsecutive = user.last_checkin === yesterdayStr();
|
|
@@ -106,9 +107,9 @@ export async function doCheckin(
|
|
|
106
107
|
context_id: ctxId,
|
|
107
108
|
});
|
|
108
109
|
|
|
109
|
-
const lines = [
|
|
110
|
-
if (bonus > 0) lines.push(
|
|
111
|
-
lines.push(
|
|
110
|
+
const lines = [t(input.locale, 'checkinDone'), t(input.locale, 'basePoints', { points: base })];
|
|
111
|
+
if (bonus > 0) lines.push(t(input.locale, 'bonusPoints', { points: bonus, days: newStreak }));
|
|
112
|
+
lines.push(t(input.locale, 'earnedPoints', { points: earned }), t(input.locale, 'currentPoints', { points: newPoints }));
|
|
112
113
|
return lines.join('\n');
|
|
113
114
|
});
|
|
114
115
|
}
|
|
@@ -116,9 +117,10 @@ export async function doCheckin(
|
|
|
116
117
|
export async function myPoints(
|
|
117
118
|
input: ConversationInput,
|
|
118
119
|
runtime: GroupSuiteRuntime,
|
|
120
|
+
commandHead?: string,
|
|
119
121
|
): Promise<string> {
|
|
120
122
|
const M = getCheckinModel(runtime.db);
|
|
121
|
-
if (!M) return '
|
|
123
|
+
if (!M) return t(input.locale, 'checkinDb');
|
|
122
124
|
const { id: userId } = resolveSender(input);
|
|
123
125
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
124
126
|
const rows = (await M.select().where({
|
|
@@ -126,16 +128,16 @@ export async function myPoints(
|
|
|
126
128
|
context_type: ctxType,
|
|
127
129
|
context_id: ctxId,
|
|
128
130
|
})) as Record<string, unknown>[];
|
|
129
|
-
if (rows.length === 0) return '
|
|
131
|
+
if (rows.length === 0) return commandHead ? t(input.locale, 'checkinHint', { command: commandHead }) : t(input.locale, 'checkinHintNoHead');
|
|
130
132
|
const u = rows[0];
|
|
131
133
|
const checkedToday = u.last_checkin === todayStr();
|
|
132
134
|
return [
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
checkedToday ?
|
|
135
|
+
t(input.locale, 'pointsTitle', { name: String(u.user_name || t(input.locale, 'user')) }),
|
|
136
|
+
t(input.locale, 'points', { points: String(u.points) }),
|
|
137
|
+
t(input.locale, 'checkinTotal', { days: String(u.total_checkins) }),
|
|
138
|
+
t(input.locale, 'checkinStreak', { days: String(u.streak) }),
|
|
139
|
+
t(input.locale, 'checkinMax', { days: String(u.max_streak) }),
|
|
140
|
+
checkedToday ? t(input.locale, 'checked') : t(input.locale, 'unchecked'),
|
|
139
141
|
].join('\n');
|
|
140
142
|
}
|
|
141
143
|
|
|
@@ -145,23 +147,23 @@ export async function pointsRank(
|
|
|
145
147
|
runtime: GroupSuiteRuntime,
|
|
146
148
|
): Promise<string> {
|
|
147
149
|
const M = getCheckinModel(runtime.db);
|
|
148
|
-
if (!M) return '
|
|
150
|
+
if (!M) return t(input.locale, 'checkinDb');
|
|
149
151
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
150
152
|
const all = (await M.select().where(
|
|
151
153
|
{ context_type: ctxType, context_id: ctxId },
|
|
152
154
|
)) as Record<string, unknown>[];
|
|
153
|
-
if (all.length === 0) return '
|
|
155
|
+
if (all.length === 0) return t(input.locale, 'checkinEmpty');
|
|
154
156
|
const sorted = all.sort((a, b) => Number(b.points || 0) - Number(a.points || 0));
|
|
155
157
|
const top = sorted.slice(0, cfg.rankSize);
|
|
156
158
|
const medals = ['🥇', '🥈', '🥉'];
|
|
157
159
|
const lines = top.map((u, i) => {
|
|
158
160
|
const prefix = i < 3 ? medals[i] : `${i + 1}.`;
|
|
159
|
-
return
|
|
161
|
+
return t(input.locale, 'pointsRow', { prefix, name: String(u.user_name || u.user_id), points: String(u.points), days: String(u.total_checkins) });
|
|
160
162
|
});
|
|
161
|
-
const title = ctxType === 'group' ? '
|
|
162
|
-
: ctxType === 'channel' ? '
|
|
163
|
+
const title = ctxType === 'group' ? t(input.locale, 'groupPoints')
|
|
164
|
+
: ctxType === 'channel' ? t(input.locale, 'channelPoints') : t(input.locale, 'privatePoints');
|
|
163
165
|
const { id: userId } = resolveSender(input);
|
|
164
166
|
const myRank = sorted.findIndex((u) => u.user_id === userId);
|
|
165
|
-
const footer = myRank >= 0 ?
|
|
167
|
+
const footer = myRank >= 0 ? t(input.locale, 'myRankFooter', { rank: myRank + 1 }) : '';
|
|
166
168
|
return `${title}\n${lines.join('\n')}${footer}`;
|
|
167
169
|
}
|
|
@@ -3,6 +3,7 @@ import { adapterFeatureId, type AdapterIndex } from 'zhin.js/adapter';
|
|
|
3
3
|
import type { ToolInvocationOrigin } from '@zhin.js/tool';
|
|
4
4
|
|
|
5
5
|
export interface ConversationInput {
|
|
6
|
+
readonly locale?: import('zhin.js/i18n').Locale;
|
|
6
7
|
readonly conversation?: DeliveryTarget;
|
|
7
8
|
readonly sender?: Readonly<{ id: string; name?: string }>;
|
|
8
9
|
readonly content?: unknown;
|