feat: 实现消息长度分布图

This commit is contained in:
digua
2026-01-22 00:10:25 +08:00
parent 21c8320ea5
commit 057432f829
8 changed files with 187 additions and 11 deletions

View File

@@ -302,6 +302,84 @@ export function getMessageTypeDistribution(sessionId: string, filter?: TimeFilte
}))
}
/**
* 获取消息长度分布(仅统计文字消息)
* 返回两组数据:
* - detail: 1-25 字逐字分布
* - grouped: 5-100+ 每5字一组
*/
export function getMessageLengthDistribution(sessionId: string, filter?: TimeFilter): {
detail: Array<{ len: number; count: number }>
grouped: Array<{ range: string; count: number }>
} {
const db = openDatabase(sessionId)
if (!db) return { detail: [], grouped: [] }
const { clause, params } = buildTimeFilter(filter)
const clauseWithSystem = buildSystemMessageFilter(clause)
// 只统计文字消息 (type = 0),并且 content 不为空
const typeCondition = clauseWithSystem
? clauseWithSystem + ' AND msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(msg.content) > 0'
: 'WHERE msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(msg.content) > 0'
// 直接获取每条消息的长度
const rows = db
.prepare(
`
SELECT LENGTH(msg.content) as len, COUNT(*) as count
FROM message msg
JOIN member m ON msg.sender_id = m.id
${typeCondition}
GROUP BY len
ORDER BY len
`
)
.all(...params) as Array<{ len: number; count: number }>
// 构建 detail1-25 逐字
const detail: Array<{ len: number; count: number }> = []
for (let i = 1; i <= 25; i++) {
const found = rows.find((r) => r.len === i)
detail.push({
len: i,
count: found ? found.count : 0,
})
}
// 构建 grouped每5字一段
const ranges5 = [
{ min: 1, max: 5, label: '1-5' },
{ min: 6, max: 10, label: '6-10' },
{ min: 11, max: 15, label: '11-15' },
{ min: 16, max: 20, label: '16-20' },
{ min: 21, max: 25, label: '21-25' },
{ min: 26, max: 30, label: '26-30' },
{ min: 31, max: 35, label: '31-35' },
{ min: 36, max: 40, label: '36-40' },
{ min: 41, max: 45, label: '41-45' },
{ min: 46, max: 50, label: '46-50' },
{ min: 51, max: 60, label: '51-60' },
{ min: 61, max: 70, label: '61-70' },
{ min: 71, max: 80, label: '71-80' },
{ min: 81, max: 100, label: '81-100' },
{ min: 101, max: Infinity, label: '100+' },
]
const grouped: Array<{ range: string; count: number }> = []
for (const r of ranges5) {
const count = rows
.filter((row) => row.len >= r.min && row.len <= r.max)
.reduce((sum, row) => sum + row.count, 0)
grouped.push({
range: r.label,
count,
})
}
return { detail, grouped }
}
/**
* 获取时间范围
*/

View File

@@ -12,6 +12,7 @@ export {
getWeekdayActivity,
getMonthlyActivity,
getYearlyActivity,
getMessageLengthDistribution,
getMessageTypeDistribution,
getTimeRange,
getMemberNameHistory,