koishi-plugin-group-analysis-mx 1.0.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/config.d.ts +53 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +376 -0
- package/lib/config.js.map +1 -0
- package/lib/cron.d.ts +8 -0
- package/lib/cron.d.ts.map +1 -0
- package/lib/cron.js +62 -0
- package/lib/cron.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +51 -0
- package/lib/index.js.map +1 -0
- package/lib/onebot/cqcode.d.ts +14 -0
- package/lib/onebot/cqcode.d.ts.map +1 -0
- package/lib/onebot/cqcode.js +92 -0
- package/lib/onebot/cqcode.js.map +1 -0
- package/lib/plugin.d.ts +4 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +41 -0
- package/lib/plugin.js.map +1 -0
- package/lib/plugins/command.d.ts +9 -0
- package/lib/plugins/command.d.ts.map +1 -0
- package/lib/plugins/command.js +196 -0
- package/lib/plugins/command.js.map +1 -0
- package/lib/service/analysis.d.ts +48 -0
- package/lib/service/analysis.d.ts.map +1 -0
- package/lib/service/analysis.js +714 -0
- package/lib/service/analysis.js.map +1 -0
- package/lib/service/llm.d.ts +43 -0
- package/lib/service/llm.d.ts.map +1 -0
- package/lib/service/llm.js +160 -0
- package/lib/service/llm.js.map +1 -0
- package/lib/service/message.d.ts +55 -0
- package/lib/service/message.d.ts.map +1 -0
- package/lib/service/message.js +527 -0
- package/lib/service/message.js.map +1 -0
- package/lib/service/renderer.d.ts +23 -0
- package/lib/service/renderer.d.ts.map +1 -0
- package/lib/service/renderer.js +298 -0
- package/lib/service/renderer.js.map +1 -0
- package/lib/skins/anime.d.ts +19 -0
- package/lib/skins/anime.d.ts.map +1 -0
- package/lib/skins/anime.js +138 -0
- package/lib/skins/anime.js.map +1 -0
- package/lib/skins/art.d.ts +19 -0
- package/lib/skins/art.d.ts.map +1 -0
- package/lib/skins/art.js +146 -0
- package/lib/skins/art.js.map +1 -0
- package/lib/skins/index.d.ts +50 -0
- package/lib/skins/index.d.ts.map +1 -0
- package/lib/skins/index.js +84 -0
- package/lib/skins/index.js.map +1 -0
- package/lib/skins/md3.d.ts +19 -0
- package/lib/skins/md3.d.ts.map +1 -0
- package/lib/skins/md3.js +147 -0
- package/lib/skins/md3.js.map +1 -0
- package/lib/skins/newspaper.d.ts +19 -0
- package/lib/skins/newspaper.d.ts.map +1 -0
- package/lib/skins/newspaper.js +141 -0
- package/lib/skins/newspaper.js.map +1 -0
- package/lib/skins/scrapbook.d.ts +20 -0
- package/lib/skins/scrapbook.d.ts.map +1 -0
- package/lib/skins/scrapbook.js +207 -0
- package/lib/skins/scrapbook.js.map +1 -0
- package/lib/skins/types.d.ts +69 -0
- package/lib/skins/types.d.ts.map +1 -0
- package/lib/skins/types.js +12 -0
- package/lib/skins/types.js.map +1 -0
- package/lib/types.d.ts +170 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/utils.d.ts +55 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +334 -0
- package/lib/utils.js.map +1 -0
- package/package.json +48 -0
- package/resources/anime/css/template_group.css +470 -0
- package/resources/anime/images/decoration_br.svg +19 -0
- package/resources/anime/images/decoration_tl.svg +24 -0
- package/resources/anime/template_group.html +108 -0
- package/resources/anime/template_user.html +99 -0
- package/resources/art/css/template_group.css +484 -0
- package/resources/art/template_group.html +77 -0
- package/resources/art/template_user.html +63 -0
- package/resources/md3/css/template_group.css +880 -0
- package/resources/md3/template_group.html +189 -0
- package/resources/md3/template_user.html +175 -0
- package/resources/newspaper/css/template_group.css +568 -0
- package/resources/newspaper/template_group.html +133 -0
- package/resources/newspaper/template_user.html +119 -0
- package/resources/scrapbook/css/style.css +1094 -0
- package/resources/scrapbook/template_group.html +115 -0
- package/resources/scrapbook/template_user.html +119 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RendererService = void 0;
|
|
7
|
+
const koishi_1 = require("koishi");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const utils_1 = require("../utils");
|
|
11
|
+
const skins_1 = require("../skins");
|
|
12
|
+
class RendererService extends koishi_1.Service {
|
|
13
|
+
config;
|
|
14
|
+
static inject = ['puppeteer'];
|
|
15
|
+
templateDir;
|
|
16
|
+
constructor(ctx, config) {
|
|
17
|
+
super(ctx, 'group_analysis_renderer', true);
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.templateDir = path_1.default.resolve(ctx.baseDir, 'data/group_analysis');
|
|
20
|
+
this.ctx.on('ready', async () => {
|
|
21
|
+
await this.init();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
getSkinPath(filename) {
|
|
25
|
+
const skin = this.config.skin || 'md3';
|
|
26
|
+
return path_1.default.resolve(this.templateDir, skin, filename);
|
|
27
|
+
}
|
|
28
|
+
async imageToBase64(url) {
|
|
29
|
+
try {
|
|
30
|
+
this.ctx.logger.debug(`转换图片为 Base64: ${url}`);
|
|
31
|
+
const response = await fetch(url);
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
36
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
37
|
+
// 根据 URL 或 Content-Type 推断 MIME 类型
|
|
38
|
+
const contentType = response.headers.get('content-type') || 'image/png';
|
|
39
|
+
const base64 = buffer.toString('base64');
|
|
40
|
+
const dataUrl = `data:${contentType};base64,${base64}`;
|
|
41
|
+
this.ctx.logger.debug(`图片已转换为 Base64,大小: ${base64.length} 字符`);
|
|
42
|
+
return dataUrl;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
this.ctx.logger.warn(`图片转换 Base64 失败: ${url}`, error);
|
|
46
|
+
// 返回一个 1x1 透明 PNG 的 Base64
|
|
47
|
+
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async init() {
|
|
51
|
+
const resourcesDir = __dirname + '/../resources';
|
|
52
|
+
const templateDir = this.templateDir;
|
|
53
|
+
const skin = this.config.skin || 'md3';
|
|
54
|
+
// Source: resources/md3 (or other skin)
|
|
55
|
+
const skinSourceDir = path_1.default.resolve(resourcesDir, skin);
|
|
56
|
+
// Destination: data/group_analysis/md3
|
|
57
|
+
const skinDestDir = path_1.default.resolve(templateDir, skin);
|
|
58
|
+
/* try {
|
|
59
|
+
await fs.access(skinDestDir)
|
|
60
|
+
} catch (error) { */
|
|
61
|
+
await fs_1.promises.mkdir(skinDestDir, { recursive: true });
|
|
62
|
+
// Copy only the configured skin directory
|
|
63
|
+
await fs_1.promises.cp(skinSourceDir, skinDestDir, { recursive: true });
|
|
64
|
+
/* } */
|
|
65
|
+
const tempHtmlFiles = await fs_1.promises
|
|
66
|
+
.readdir(skinDestDir)
|
|
67
|
+
.then((files) => files.filter((file) => file.endsWith('.html') && !file.startsWith('template')))
|
|
68
|
+
.catch(() => []);
|
|
69
|
+
for (const file of tempHtmlFiles) {
|
|
70
|
+
await fs_1.promises.unlink(path_1.default.resolve(skinDestDir, file));
|
|
71
|
+
}
|
|
72
|
+
const page = await this.ctx.puppeteer.page();
|
|
73
|
+
try {
|
|
74
|
+
await page.goto('file://' + this.getSkinPath('template_user.html'), {
|
|
75
|
+
waitUntil: 'domcontentloaded'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
this.ctx.logger.error('初始化模板文件时发生错误:', error);
|
|
80
|
+
}
|
|
81
|
+
this.ctx.setTimeout(async () => {
|
|
82
|
+
try {
|
|
83
|
+
page.close();
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
this.ctx.logger.error('关闭页面时发生错误:', error);
|
|
87
|
+
}
|
|
88
|
+
}, 3 * 60 * 1000);
|
|
89
|
+
}
|
|
90
|
+
async renderGroupAnalysisToPdf(data) {
|
|
91
|
+
let theme = this.config.theme;
|
|
92
|
+
if (theme === 'auto') {
|
|
93
|
+
const hour = new Date().getHours();
|
|
94
|
+
theme = hour >= 19 || hour < 6 ? 'dark' : 'light';
|
|
95
|
+
}
|
|
96
|
+
const page = await this._renderGroupAnalysis(data, theme);
|
|
97
|
+
const pdfBuffer = await page.pdf({ format: 'A4' });
|
|
98
|
+
await page.close();
|
|
99
|
+
return pdfBuffer;
|
|
100
|
+
}
|
|
101
|
+
async renderGroupAnalysis(data, config) {
|
|
102
|
+
try {
|
|
103
|
+
let theme = config.theme;
|
|
104
|
+
if (theme === 'auto') {
|
|
105
|
+
const hour = new Date().getHours();
|
|
106
|
+
theme = hour >= 19 || hour < 6 ? 'dark' : 'light';
|
|
107
|
+
}
|
|
108
|
+
const page = await this._renderGroupAnalysis(data, theme);
|
|
109
|
+
// 找到页面中的 container 元素
|
|
110
|
+
const renderer = skins_1.skinRegistry.getSafe(config.skin || 'md3');
|
|
111
|
+
const selector = renderer.containerSelector;
|
|
112
|
+
const element = await page.$(selector);
|
|
113
|
+
if (!element) {
|
|
114
|
+
await page.close();
|
|
115
|
+
throw new Error(`无法在渲染的 HTML 中找到 ${selector} 元素。`);
|
|
116
|
+
}
|
|
117
|
+
const imageBuffer = await element.screenshot({});
|
|
118
|
+
await page.close();
|
|
119
|
+
this.ctx.logger.info('图片渲染成功!');
|
|
120
|
+
return imageBuffer;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
this.ctx.logger.error('渲染报告图片时发生错误:', error);
|
|
124
|
+
if (error instanceof Error) {
|
|
125
|
+
return `图片渲染失败: ${error.message}`;
|
|
126
|
+
}
|
|
127
|
+
return '图片渲染失败,发生未知错误。';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async _renderGroupAnalysis(data, theme) {
|
|
131
|
+
// 检查 puppeteer 是否可用
|
|
132
|
+
if (!this.ctx.puppeteer) {
|
|
133
|
+
throw new Error('Puppeteer service is not available.');
|
|
134
|
+
}
|
|
135
|
+
const templatePath = this.getSkinPath('template_group.html');
|
|
136
|
+
const randomId = Math.random().toString(36).substring(2, 15);
|
|
137
|
+
const skin = this.config.skin || 'md3';
|
|
138
|
+
const outTemplateHtmlPath = path_1.default.resolve(this.templateDir, skin, `${randomId}.html`);
|
|
139
|
+
const dynamicAvatarUrl = data.userStats?.[Math.floor(Math.random() * data.userStats.length)]
|
|
140
|
+
?.avatar ||
|
|
141
|
+
'https://cravatar.cn/avatar/00000000000000000000000000000000?d=mp';
|
|
142
|
+
// 将头像转换为 Base64
|
|
143
|
+
const dynamicAvatarBase64 = await this.imageToBase64(dynamicAvatarUrl);
|
|
144
|
+
// 读取模板文件并替换占位符
|
|
145
|
+
const templateHtml = await fs_1.promises.readFile(templatePath, 'utf-8');
|
|
146
|
+
const filledHtml = (0, utils_1.renderTemplate)(templateHtml, {
|
|
147
|
+
groupName: data.groupName,
|
|
148
|
+
analysisDate: data.analysisDate,
|
|
149
|
+
totalMessages: data.totalMessages.toString(),
|
|
150
|
+
totalParticipants: data.totalParticipants.toString(),
|
|
151
|
+
totalChars: data.totalChars.toString(),
|
|
152
|
+
mostActivePeriod: data.mostActivePeriod,
|
|
153
|
+
emojiCount: (data.emojiCount || 0).toString(),
|
|
154
|
+
userStats: (0, utils_1.formatUserStats)(data.userStats, skin),
|
|
155
|
+
topics: (0, utils_1.formatTopics)(data.topics || [], skin),
|
|
156
|
+
userTitles: (0, utils_1.formatUserTitles)(data.userTitles || [], skin),
|
|
157
|
+
activeHoursChart: (0, utils_1.generateActiveHoursChart)(data.activeHoursData || {}, skin),
|
|
158
|
+
goldenQuotes: (0, utils_1.formatGoldenQuotes)(data.goldenQuotes || [], skin),
|
|
159
|
+
theme,
|
|
160
|
+
dynamicAvatarUrl: dynamicAvatarBase64
|
|
161
|
+
});
|
|
162
|
+
// 写入临时 HTML 文件
|
|
163
|
+
await fs_1.promises.writeFile(outTemplateHtmlPath, filledHtml);
|
|
164
|
+
this.ctx.logger.info('HTML 模板填充完成,正在调用 Puppeteer 进行渲染...');
|
|
165
|
+
const page = await this.ctx.puppeteer.page();
|
|
166
|
+
// 重新加载页面并使用 goto 访问本地文件
|
|
167
|
+
await page.goto('file://' + outTemplateHtmlPath, {
|
|
168
|
+
waitUntil: 'domcontentloaded'
|
|
169
|
+
});
|
|
170
|
+
this.ctx.logger.info('网页加载完成,开始等待字体加载。');
|
|
171
|
+
// 等待字体加载完成
|
|
172
|
+
await page.evaluate(() => document.fonts.ready);
|
|
173
|
+
this.ctx.logger.info('字体加载完成。');
|
|
174
|
+
// 设置 3 分钟后自动删除临时文件
|
|
175
|
+
this.ctx.setTimeout(async () => {
|
|
176
|
+
try {
|
|
177
|
+
await fs_1.promises.unlink(outTemplateHtmlPath);
|
|
178
|
+
this.ctx.logger.debug(`已删除临时文件: ${outTemplateHtmlPath}`);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
this.ctx.logger.warn(`删除临时文件失败: ${error}`);
|
|
182
|
+
}
|
|
183
|
+
}, 3 * 60 * 1000); // 3 分钟
|
|
184
|
+
return page;
|
|
185
|
+
}
|
|
186
|
+
async renderUserPersona(data, username, avatar, config) {
|
|
187
|
+
try {
|
|
188
|
+
let theme = config.theme;
|
|
189
|
+
if (theme === 'auto') {
|
|
190
|
+
const hour = new Date().getHours();
|
|
191
|
+
theme = hour >= 19 || hour < 6 ? 'dark' : 'light';
|
|
192
|
+
}
|
|
193
|
+
const page = await this._renderUserPersona(data, username, avatar, theme);
|
|
194
|
+
const renderer = skins_1.skinRegistry.getSafe(config.skin || 'md3');
|
|
195
|
+
const selector = renderer.containerSelector;
|
|
196
|
+
const element = await page.$(selector);
|
|
197
|
+
if (!element) {
|
|
198
|
+
await page.close();
|
|
199
|
+
throw new Error(`无法在渲染的 HTML 中找到 ${selector} 元素。`);
|
|
200
|
+
}
|
|
201
|
+
const imageBuffer = await element.screenshot();
|
|
202
|
+
await page.close();
|
|
203
|
+
this.ctx.logger.info('用户画像图片渲染成功!');
|
|
204
|
+
return imageBuffer;
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
this.ctx.logger.error('渲染用户画像图片时发生错误:', error);
|
|
208
|
+
if (error instanceof Error) {
|
|
209
|
+
return `图片渲染失败: ${error.message}`;
|
|
210
|
+
}
|
|
211
|
+
return '图片渲染失败,发生未知错误。';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async _renderUserPersona(data, username, avatar, theme) {
|
|
215
|
+
if (!this.ctx.puppeteer) {
|
|
216
|
+
throw new Error('Puppeteer service is not available.');
|
|
217
|
+
}
|
|
218
|
+
const templatePath = this.getSkinPath('template_user.html');
|
|
219
|
+
const randomId = Math.random().toString(36).substring(2, 15);
|
|
220
|
+
const skin = this.config.skin || 'md3';
|
|
221
|
+
const outTemplateHtmlPath = path_1.default.resolve(this.templateDir, skin, `${randomId}.html`);
|
|
222
|
+
const renderer = skins_1.skinRegistry.getSafe(skin);
|
|
223
|
+
const formatTags = (tags) => {
|
|
224
|
+
if (renderer.formatTags) {
|
|
225
|
+
return renderer.formatTags(tags);
|
|
226
|
+
}
|
|
227
|
+
// Fallback if skin doesn't implement formatTags
|
|
228
|
+
if (!tags || tags.length === 0) {
|
|
229
|
+
return '<div class="empty-state">暂无数据</div>';
|
|
230
|
+
}
|
|
231
|
+
return tags.map((tag) => `<div class="chip">${tag}</div>`).join('');
|
|
232
|
+
};
|
|
233
|
+
const formatEvidence = (items) => {
|
|
234
|
+
if (renderer.formatEvidence) {
|
|
235
|
+
return renderer.formatEvidence(items);
|
|
236
|
+
}
|
|
237
|
+
// Fallback if skin doesn't implement formatEvidence
|
|
238
|
+
if (!items || items.length === 0) {
|
|
239
|
+
return '<div class="empty-state">暂无事实依据</div>';
|
|
240
|
+
}
|
|
241
|
+
const cards = items
|
|
242
|
+
.map((item) => {
|
|
243
|
+
const quoteHtml = (item || '')
|
|
244
|
+
.split('\n')
|
|
245
|
+
.map((line) => line.trim())
|
|
246
|
+
.filter(Boolean)
|
|
247
|
+
.join('<br/>');
|
|
248
|
+
return `
|
|
249
|
+
<div class="card outlined-card evidence-card">
|
|
250
|
+
<p>${quoteHtml}</p>
|
|
251
|
+
</div>
|
|
252
|
+
`;
|
|
253
|
+
})
|
|
254
|
+
.join('');
|
|
255
|
+
return `<div class="card-grid">${cards}</div>`;
|
|
256
|
+
};
|
|
257
|
+
const dynamicAvatarUrl = avatar ||
|
|
258
|
+
'https://cravatar.cn/avatar/00000000000000000000000000000000?d=mp';
|
|
259
|
+
// 将头像转换为 Base64
|
|
260
|
+
const dynamicAvatarBase64 = await this.imageToBase64(dynamicAvatarUrl);
|
|
261
|
+
const templateHtml = await fs_1.promises.readFile(templatePath, 'utf-8');
|
|
262
|
+
const filledHtml = (0, utils_1.renderTemplate)(templateHtml, {
|
|
263
|
+
avatar: dynamicAvatarBase64,
|
|
264
|
+
username,
|
|
265
|
+
analysisDate: data.analysisDate || '暂无记录',
|
|
266
|
+
summary: data.summary || '暂无摘要',
|
|
267
|
+
keyTraits: formatTags(data.keyTraits),
|
|
268
|
+
interests: formatTags(data.interests),
|
|
269
|
+
communicationStyle: data.communicationStyle || '暂无记录',
|
|
270
|
+
evidence: formatEvidence(data.evidence),
|
|
271
|
+
theme,
|
|
272
|
+
dynamicAvatarUrl: dynamicAvatarBase64
|
|
273
|
+
});
|
|
274
|
+
await fs_1.promises.writeFile(outTemplateHtmlPath, filledHtml);
|
|
275
|
+
this.ctx.logger.info('用户画像 HTML 模板填充完成,正在调用 Puppeteer 进行渲染...');
|
|
276
|
+
const page = await this.ctx.puppeteer.page();
|
|
277
|
+
// 重新加载页面并使用 goto 访问本地文件
|
|
278
|
+
await page.goto('file://' + outTemplateHtmlPath, {
|
|
279
|
+
waitUntil: 'domcontentloaded'
|
|
280
|
+
});
|
|
281
|
+
this.ctx.logger.info('网页加载完成,开始等待字体加载。');
|
|
282
|
+
// 等待字体加载完成
|
|
283
|
+
await page.evaluate(() => document.fonts.ready);
|
|
284
|
+
this.ctx.logger.info('字体加载完成。');
|
|
285
|
+
this.ctx.setTimeout(async () => {
|
|
286
|
+
try {
|
|
287
|
+
await fs_1.promises.unlink(outTemplateHtmlPath);
|
|
288
|
+
this.ctx.logger.debug(`已删除临时文件: ${outTemplateHtmlPath}`);
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
this.ctx.logger.warn(`删除临时文件失败: ${error}`);
|
|
292
|
+
}
|
|
293
|
+
}, 3 * 60 * 1000);
|
|
294
|
+
return page;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
exports.RendererService = RendererService;
|
|
298
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/service/renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SkinRenderer } from './types';
|
|
2
|
+
import { GroupAnalysisResult, UserStats } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Anime skin renderer (Updated to Nahida/Sumeru Style 3.0)
|
|
5
|
+
* Cute, 2D-first, Sticker/Card aesthetics.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AnimeSkinRenderer implements SkinRenderer {
|
|
8
|
+
readonly id = "anime";
|
|
9
|
+
readonly name = "\u4E8C\u6B21\u5143\u98CE\u683C";
|
|
10
|
+
readonly containerSelector = ".nahida-container";
|
|
11
|
+
formatUserStats(userStats: UserStats[]): string;
|
|
12
|
+
formatGoldenQuotes(quotes: GroupAnalysisResult['goldenQuotes']): string;
|
|
13
|
+
formatUserTitles(userTitles: GroupAnalysisResult['userTitles']): string;
|
|
14
|
+
formatTopics(topics: GroupAnalysisResult['topics']): string;
|
|
15
|
+
generateActiveHoursChart(activeHours: Record<number, number>): string;
|
|
16
|
+
formatTags(tags: string[] | undefined): string;
|
|
17
|
+
formatEvidence(items: string[] | '无' | undefined): string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=anime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anime.d.ts","sourceRoot":"","sources":["../../src/skins/anime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAE,MAAM,SAAS,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzD;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IAClD,QAAQ,CAAC,EAAE,WAAU;IACrB,QAAQ,CAAC,IAAI,oCAAU;IACvB,QAAQ,CAAC,iBAAiB,uBAAsB;IAEhD,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM;IAyB/C,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,CAAC,cAAc,CAAC,GAAG,MAAM;IAmBvE,gBAAgB,CAAC,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,GAAG,MAAM;IA0BvE,YAAY,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GAAG,MAAM;IAkB3D,wBAAwB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;IA2BrE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM;IAU9C,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,SAAS,GAAG,MAAM;CAqB5D"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AnimeSkinRenderer = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
/**
|
|
6
|
+
* Anime skin renderer (Updated to Nahida/Sumeru Style 3.0)
|
|
7
|
+
* Cute, 2D-first, Sticker/Card aesthetics.
|
|
8
|
+
*/
|
|
9
|
+
class AnimeSkinRenderer {
|
|
10
|
+
id = 'anime';
|
|
11
|
+
name = '二次元风格';
|
|
12
|
+
containerSelector = '.nahida-container';
|
|
13
|
+
formatUserStats(userStats) {
|
|
14
|
+
if (!userStats || userStats.length === 0) {
|
|
15
|
+
return '<div class="empty-state">暂无用户统计信息</div>';
|
|
16
|
+
}
|
|
17
|
+
return userStats
|
|
18
|
+
.map((user) => `
|
|
19
|
+
<div class="char-box">
|
|
20
|
+
<img src="${(0, types_1.getAvatarUrl)(user.userId)}" alt="avatar" class="char-avatar">
|
|
21
|
+
<div class="char-content">
|
|
22
|
+
<div class="char-name">${user.nickname}</div>
|
|
23
|
+
<div class="char-detail">
|
|
24
|
+
<span>发言: <strong>${user.messageCount}</strong></span>
|
|
25
|
+
<span>回复: <strong>${(user.replyRatio * 100).toFixed(0)}%</strong></span>
|
|
26
|
+
<span>字数: <strong>${user.charCount}</strong></span>
|
|
27
|
+
<span>夜猫: <strong>${(user.nightRatio * 100).toFixed(0)}%</strong></span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
`)
|
|
32
|
+
.join('');
|
|
33
|
+
}
|
|
34
|
+
formatGoldenQuotes(quotes) {
|
|
35
|
+
if (!quotes || quotes.length === 0) {
|
|
36
|
+
return '<div class="empty-state">本次未发现逆天神人发言</div>';
|
|
37
|
+
}
|
|
38
|
+
return quotes
|
|
39
|
+
.map((quote) => `
|
|
40
|
+
<div class="bubble">
|
|
41
|
+
<div class="bubble-text">"${quote.content}"</div>
|
|
42
|
+
<div class="bubble-meta">
|
|
43
|
+
— ${quote.sender}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
`)
|
|
47
|
+
.join('');
|
|
48
|
+
}
|
|
49
|
+
formatUserTitles(userTitles) {
|
|
50
|
+
if (!userTitles || userTitles.length === 0) {
|
|
51
|
+
return '<div class="empty-state">本次无人获得特殊称号</div>';
|
|
52
|
+
}
|
|
53
|
+
return userTitles
|
|
54
|
+
.map((title) => `
|
|
55
|
+
<div class="char-box">
|
|
56
|
+
<img src="${(0, types_1.getAvatarUrl)(title.id)}" alt="avatar" class="char-avatar">
|
|
57
|
+
<div class="char-content">
|
|
58
|
+
<div class="char-name">${title.name}</div>
|
|
59
|
+
<div style="margin-bottom: 6px;">
|
|
60
|
+
<span class="char-badge">${title.title}</span>
|
|
61
|
+
${title.mbti && title.mbti !== 'N/A' ? `<span class="char-badge" style="background:#E1BEE7;">${title.mbti}</span>` : ''}
|
|
62
|
+
</div>
|
|
63
|
+
<div class="char-detail" style="font-style:italic;">
|
|
64
|
+
${title.reason}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
`)
|
|
69
|
+
.join('');
|
|
70
|
+
}
|
|
71
|
+
formatTopics(topics) {
|
|
72
|
+
if (!topics || topics.length === 0) {
|
|
73
|
+
return '<div class="empty-state">本次无明显讨论话题</div>';
|
|
74
|
+
}
|
|
75
|
+
return topics
|
|
76
|
+
.map((topic) => `
|
|
77
|
+
<div class="bubble">
|
|
78
|
+
<div style="font-weight:bold; color:var(--color-primary); margin-bottom:4px; font-size:18px;"># ${topic.topic}</div>
|
|
79
|
+
<div class="bubble-text" style="font-size: 14px;">${topic.detail}</div>
|
|
80
|
+
<div class="bubble-meta">参与者: ${topic.contributors.join(', ')}</div>
|
|
81
|
+
</div>
|
|
82
|
+
`)
|
|
83
|
+
.join('');
|
|
84
|
+
}
|
|
85
|
+
generateActiveHoursChart(activeHours) {
|
|
86
|
+
const values = Object.values(activeHours);
|
|
87
|
+
const maxCount = values.length > 0 ? Math.max(...values) : 0;
|
|
88
|
+
const chartBars = [];
|
|
89
|
+
for (let i = 0; i < 24; i++) {
|
|
90
|
+
const count = activeHours[i] || 0;
|
|
91
|
+
let barHeight = maxCount > 0 ? (count / maxCount) * 100 : 0;
|
|
92
|
+
if (count > 0 && barHeight < 10) {
|
|
93
|
+
barHeight = 10; // Min height for visibility
|
|
94
|
+
}
|
|
95
|
+
chartBars.push(`
|
|
96
|
+
<div class="chart-bar-group" title="${i}:00 - ${count} 条消息">
|
|
97
|
+
<div class="chart-bar" style="height: ${barHeight}%;"></div>
|
|
98
|
+
<span class="chart-label">${String(i).padStart(2, '0')}</span>
|
|
99
|
+
</div>
|
|
100
|
+
`);
|
|
101
|
+
}
|
|
102
|
+
return `
|
|
103
|
+
<div class="chart-container">
|
|
104
|
+
${chartBars.join('')}
|
|
105
|
+
</div>
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
formatTags(tags) {
|
|
109
|
+
if (!tags || tags.length === 0) {
|
|
110
|
+
return '<div class="empty-state">暂无数据</div>';
|
|
111
|
+
}
|
|
112
|
+
return tags
|
|
113
|
+
.map((tag) => `<span class="tag">${tag}</span>`)
|
|
114
|
+
.join('');
|
|
115
|
+
}
|
|
116
|
+
formatEvidence(items) {
|
|
117
|
+
if (!items || items.length === 0 || items === '无') {
|
|
118
|
+
return '<div class="empty-state">暂无事实依据</div>';
|
|
119
|
+
}
|
|
120
|
+
const listItems = items
|
|
121
|
+
.map((item) => {
|
|
122
|
+
const quoteHtml = (item || '')
|
|
123
|
+
.split('\n')
|
|
124
|
+
.map((line) => line.trim())
|
|
125
|
+
.filter(Boolean)
|
|
126
|
+
.join('<br/>');
|
|
127
|
+
return `
|
|
128
|
+
<div class="evidence-item">
|
|
129
|
+
${quoteHtml}
|
|
130
|
+
</div>
|
|
131
|
+
`;
|
|
132
|
+
})
|
|
133
|
+
.join('');
|
|
134
|
+
return `<div>${listItems}</div>`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.AnimeSkinRenderer = AnimeSkinRenderer;
|
|
138
|
+
//# sourceMappingURL=anime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anime.js","sourceRoot":"","sources":["../../src/skins/anime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SkinRenderer } from './types';
|
|
2
|
+
import { GroupAnalysisResult, UserStats } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Art Style Skin Renderer
|
|
5
|
+
* A minimal, high-end, artistic line style skin
|
|
6
|
+
*/
|
|
7
|
+
export declare class ArtSkinRenderer implements SkinRenderer {
|
|
8
|
+
readonly id = "art";
|
|
9
|
+
readonly name = "Art Style";
|
|
10
|
+
readonly containerSelector = ".container";
|
|
11
|
+
formatUserStats(userStats: UserStats[]): string;
|
|
12
|
+
formatGoldenQuotes(quotes: GroupAnalysisResult['goldenQuotes']): string;
|
|
13
|
+
formatUserTitles(userTitles: GroupAnalysisResult['userTitles']): string;
|
|
14
|
+
formatTopics(topics: GroupAnalysisResult['topics']): string;
|
|
15
|
+
generateActiveHoursChart(activeHours: Record<number, number>): string;
|
|
16
|
+
formatTags(tags: string[] | undefined): string;
|
|
17
|
+
formatEvidence(items: string[] | '无' | undefined): string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=art.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"art.d.ts","sourceRoot":"","sources":["../../src/skins/art.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAE,MAAM,SAAS,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzD;;;GAGG;AACH,qBAAa,eAAgB,YAAW,YAAY;IAChD,QAAQ,CAAC,EAAE,SAAQ;IACnB,QAAQ,CAAC,IAAI,eAAc;IAC3B,QAAQ,CAAC,iBAAiB,gBAAe;IAEzC,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM;IAyB/C,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,CAAC,cAAc,CAAC,GAAG,MAAM;IAoBvE,gBAAgB,CAAC,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,GAAG,MAAM;IAqBvE,YAAY,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GAAG,MAAM;IAkB3D,wBAAwB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;IA8CrE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM;IAQ9C,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,SAAS,GAAG,MAAM;CAsB5D"}
|
package/lib/skins/art.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArtSkinRenderer = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
/**
|
|
6
|
+
* Art Style Skin Renderer
|
|
7
|
+
* A minimal, high-end, artistic line style skin
|
|
8
|
+
*/
|
|
9
|
+
class ArtSkinRenderer {
|
|
10
|
+
id = 'art';
|
|
11
|
+
name = 'Art Style';
|
|
12
|
+
containerSelector = '.container';
|
|
13
|
+
formatUserStats(userStats) {
|
|
14
|
+
if (!userStats || userStats.length === 0) {
|
|
15
|
+
return '<div class="empty-state">暂无用户统计信息</div>';
|
|
16
|
+
}
|
|
17
|
+
return userStats
|
|
18
|
+
.map((user) => `
|
|
19
|
+
<div class="user-stat-card">
|
|
20
|
+
<img src="${(0, types_1.getAvatarUrl)(user.userId)}" alt="avatar" class="avatar">
|
|
21
|
+
<div class="user-details">
|
|
22
|
+
<div class="nickname">${user.nickname}</div>
|
|
23
|
+
<div class="stats-grid">
|
|
24
|
+
<span>发言: <strong>${user.messageCount}</strong></span>
|
|
25
|
+
<span>字数: <strong>${user.charCount}</strong></span>
|
|
26
|
+
<span>回复: <strong>${(user.replyRatio * 100).toFixed(0)}%</strong></span>
|
|
27
|
+
<span>夜猫: <strong>${(user.nightRatio * 100).toFixed(0)}%</strong></span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
`)
|
|
32
|
+
.join('');
|
|
33
|
+
}
|
|
34
|
+
formatGoldenQuotes(quotes) {
|
|
35
|
+
if (!quotes || quotes.length === 0) {
|
|
36
|
+
return '<div class="empty-state">本次未发现逆天神人发言</div>';
|
|
37
|
+
}
|
|
38
|
+
return quotes
|
|
39
|
+
.map((quote) => `
|
|
40
|
+
<div class="quote-card">
|
|
41
|
+
<div class="quote-content">${quote.content}</div>
|
|
42
|
+
<div class="quote-footer">
|
|
43
|
+
<div class="quote-sender">— ${quote.sender}</div>
|
|
44
|
+
<div class="quote-reason">${quote.reason}</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
`)
|
|
48
|
+
.join('');
|
|
49
|
+
}
|
|
50
|
+
formatUserTitles(userTitles) {
|
|
51
|
+
if (!userTitles || userTitles.length === 0) {
|
|
52
|
+
return '<div class="empty-state">本次无人获得特殊称号</div>';
|
|
53
|
+
}
|
|
54
|
+
return userTitles
|
|
55
|
+
.map((title) => `
|
|
56
|
+
<div class="title-card">
|
|
57
|
+
<img src="${(0, types_1.getAvatarUrl)(title.id)}" alt="avatar" class="avatar">
|
|
58
|
+
<div class="title-details">
|
|
59
|
+
<div class="nickname">${title.name}</div>
|
|
60
|
+
<div class="title-badge">${title.mbti && title.mbti !== 'N/A' ? `${title.title} | ${title.mbti}` : title.title}</div>
|
|
61
|
+
<p class="title-reason">${title.reason}</p>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
`)
|
|
65
|
+
.join('');
|
|
66
|
+
}
|
|
67
|
+
formatTopics(topics) {
|
|
68
|
+
if (!topics || topics.length === 0) {
|
|
69
|
+
return '<div class="empty-state">本次无明显讨论话题</div>';
|
|
70
|
+
}
|
|
71
|
+
return topics
|
|
72
|
+
.map((topic) => `
|
|
73
|
+
<div class="topic-card">
|
|
74
|
+
<div class="topic-title">${topic.topic}</div>
|
|
75
|
+
<div class="topic-contributors">CONTRIBUTORS: ${topic.contributors.join(', ')}</div>
|
|
76
|
+
<p class="topic-detail">${topic.detail}</p>
|
|
77
|
+
</div>
|
|
78
|
+
`)
|
|
79
|
+
.join('');
|
|
80
|
+
}
|
|
81
|
+
generateActiveHoursChart(activeHours) {
|
|
82
|
+
const values = Object.values(activeHours);
|
|
83
|
+
const maxCount = values.length > 0 ? Math.max(...values) : 0;
|
|
84
|
+
const chartBars = [];
|
|
85
|
+
// The container `.activity-bar` is effective 180px tall (200px - 20px padding).
|
|
86
|
+
// Label approx 20px, Count approx 20px.
|
|
87
|
+
// Max bar height approx 140px to be safe.
|
|
88
|
+
const maxBarHeight = 140;
|
|
89
|
+
for (let i = 0; i < 24; i++) {
|
|
90
|
+
const count = activeHours[i] || 0;
|
|
91
|
+
let barHeight = maxCount > 0 ? (count / maxCount) * maxBarHeight : 0;
|
|
92
|
+
if (count > 0 && barHeight < 2) {
|
|
93
|
+
barHeight = 2; // Min visible height
|
|
94
|
+
}
|
|
95
|
+
const percentage = maxCount > 0 ? Math.round((count / maxCount) * 100) : 0;
|
|
96
|
+
const barStyle = barHeight > 0
|
|
97
|
+
? `style="height: ${barHeight}px !important;"`
|
|
98
|
+
: `style="height: 0px !important;"`;
|
|
99
|
+
chartBars.push(`
|
|
100
|
+
<div class="activity-bar" title="${i}:00 - ${count} messages (${percentage}%)">
|
|
101
|
+
<div class="activity-bar-count">${count > 0 ? count : ''}</div>
|
|
102
|
+
<div class="activity-bar-bar" ${barStyle}></div>
|
|
103
|
+
<span class="activity-bar-label">${String(i).padStart(2, '0')}</span>
|
|
104
|
+
</div>
|
|
105
|
+
`);
|
|
106
|
+
}
|
|
107
|
+
return `
|
|
108
|
+
<div class="activity-chart-container">
|
|
109
|
+
<div class="activity-chart">
|
|
110
|
+
${chartBars.join('')}
|
|
111
|
+
</div>
|
|
112
|
+
<div class="chart-legend">
|
|
113
|
+
24H ACTIVITY DISTRIBUTION (PEAK: ${maxCount})
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
formatTags(tags) {
|
|
119
|
+
if (!tags || tags.length === 0) {
|
|
120
|
+
return '<div class="empty-state">暂无数据</div>';
|
|
121
|
+
}
|
|
122
|
+
return tags.map((tag) => `<div class="chip">${tag}</div>`).join('');
|
|
123
|
+
}
|
|
124
|
+
formatEvidence(items) {
|
|
125
|
+
if (!items || items.length === 0 || items === '无') {
|
|
126
|
+
return '<div class="empty-state">暂无事实依据</div>';
|
|
127
|
+
}
|
|
128
|
+
const cards = items
|
|
129
|
+
.map((item) => {
|
|
130
|
+
const quoteHtml = (item || '')
|
|
131
|
+
.split('\n')
|
|
132
|
+
.map((line) => line.trim())
|
|
133
|
+
.filter(Boolean)
|
|
134
|
+
.join('<br/>');
|
|
135
|
+
return `
|
|
136
|
+
<div class="card outlined-card evidence-card">
|
|
137
|
+
<p>${quoteHtml}</p>
|
|
138
|
+
</div>
|
|
139
|
+
`;
|
|
140
|
+
})
|
|
141
|
+
.join('');
|
|
142
|
+
return `<div class="card-grid">${cards}</div>`;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.ArtSkinRenderer = ArtSkinRenderer;
|
|
146
|
+
//# sourceMappingURL=art.js.map
|