Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions docs/member-relationship-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Member Relationship Model (Group Chat)

## Goal

Infer closer member relationships in group chat by combining:

1. Explicit interaction signal (`@mentions`)
2. Temporal adjacency signal (members speaking near each other in time)

## Scoring

For each member pair `(A, B)`:

- `mentionCount(A,B)`: undirected mention count (`A->B + B->A`)
- `temporalTurns(A,B)`: count of adjacent message turns between `A` and `B` within time window
- `temporalScore(A,B)`: `sum(exp(-delta / decaySeconds))` over adjacent turns

Normalize each signal across all pairs:

- `mentionNorm = mentionCount / maxMentionCount`
- `temporalNorm = temporalScore / maxTemporalScore`

Final closeness:

`closeness = mentionWeight * mentionNorm + temporalWeight * temporalNorm`

## Default Parameters

- `windowSeconds = 300`
- `decaySeconds = 120`
- `mentionWeight = 0.6`
- `temporalWeight = 0.4`
- `minScore = 0.12`
- `minTemporalTurns = 2`

## Current Implementation

Script: `scripts/generate-member-relationship-graph.cjs`

Run:

```bash
pnpm run analyze:relationship
```

Outputs:

- `data/member-relationship-model.json`: nodes, edges, score components
- `data/member-relationship-graph.mmd`: Mermaid graph

Adjust weights (example: emphasize temporal closeness):

```bash
node scripts/generate-member-relationship-graph.cjs \
--mention-weight 0.2 \
--temporal-weight 0.8 \
--min-score 0.03
```

## App Integration Status

Integrated into app pipeline:

1. Worker query: `electron/main/worker/query/advanced/social.ts` (`getRelationshipGraph`)
2. IPC handler: `electron/main/ipc/chat.ts` (`chat:getRelationshipGraph`)
3. Preload API: `electron/preload/apis/chat.ts` (`chatApi.getRelationshipGraph`)
4. UI: `src/components/view/InteractionView.vue` (new relationship mode + parameter controls)
9 changes: 9 additions & 0 deletions electron/main/database/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ export function checkMigrationNeeded(): {
const db = new Database(dbPath, { readonly: true })
db.pragma('journal_mode = WAL')

// 仅迁移聊天会话数据库,跳过其他业务库(如 AI 会话索引库)
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all() as Array<{ name: string }>
const tableSet = new Set(tables.map((t) => t.name))
const isChatSessionDb = tableSet.has('meta') && tableSet.has('member') && tableSet.has('message')
if (!isChatSessionDb) {
db.close()
continue
}

// 获取当前 schema_version
const metaTableInfo = db.prepare('PRAGMA table_info(meta)').all() as Array<{ name: string }>
const hasVersionColumn = metaTableInfo.some((col) => col.name === 'schema_version')
Expand Down
54 changes: 53 additions & 1 deletion electron/main/ipc/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ export function registerChatHandlers(ctx: IpcContext): void {
*/
ipcMain.handle(
'chat:getMentionGraph',
async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
async (_, sessionId: string, filter?: { startTs?: number; endTs?: number; memberId?: number | null }) => {
try {
return await worker.getMentionGraph(sessionId, filter)
} catch (error) {
Expand All @@ -513,6 +513,58 @@ export function registerChatHandlers(ctx: IpcContext): void {
}
)

/**
* 获取成员关系模型图(@ + 时间相邻共现)
*/
ipcMain.handle(
'chat:getRelationshipGraph',
async (
_,
sessionId: string,
filter?: { startTs?: number; endTs?: number; memberId?: number | null },
options?: {
mentionWeight?: number
temporalWeight?: number
reciprocityWeight?: number
windowSeconds?: number
decaySeconds?: number
minScore?: number
minTemporalTurns?: number
topEdges?: number
}
) => {
try {
return await worker.getRelationshipGraph(sessionId, filter, options)
} catch (error) {
console.error('获取成员关系模型图失败:', error)
return {
nodes: [],
links: [],
maxLinkValue: 0,
communities: [],
stats: {
totalMembers: 0,
involvedMembers: 0,
rawEdgeCount: 0,
keptEdges: 0,
maxMentionCount: 0,
maxTemporalScore: 0,
},
options: {
mentionWeight: 0.45,
temporalWeight: 0.4,
reciprocityWeight: 0.15,
windowSeconds: 300,
decaySeconds: 120,
minScore: 0.12,
minTemporalTurns: 2,
topEdges: 120,
},
}
}
}
)

/**
* 获取含笑量分析数据
*/
Expand Down
2 changes: 2 additions & 0 deletions electron/main/worker/dbWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
getDivingAnalysis,
getMentionAnalysis,
getMentionGraph,
getRelationshipGraph,
getLaughAnalysis,
getMemeBattleAnalysis,
getCheckInAnalysis,
Expand Down Expand Up @@ -122,6 +123,7 @@ const syncHandlers: Record<string, (payload: any) => any> = {
getDivingAnalysis: (p) => getDivingAnalysis(p.sessionId, p.filter),
getMentionAnalysis: (p) => getMentionAnalysis(p.sessionId, p.filter),
getMentionGraph: (p) => getMentionGraph(p.sessionId, p.filter),
getRelationshipGraph: (p) => getRelationshipGraph(p.sessionId, p.filter, p.options),
getLaughAnalysis: (p) => getLaughAnalysis(p.sessionId, p.filter, p.keywords),
getMemeBattleAnalysis: (p) => getMemeBattleAnalysis(p.sessionId, p.filter),
getCheckInAnalysis: (p) => getCheckInAnalysis(p.sessionId, p.filter),
Expand Down
14 changes: 11 additions & 3 deletions electron/main/worker/query/advanced/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export { getNightOwlAnalysis, getDragonKingAnalysis, getDivingAnalysis, getCheck
// 行为分析:斗图
export { getMemeBattleAnalysis } from './behavior'

// 社交分析:@ 互动、含笑量
export { getMentionAnalysis, getMentionGraph, getLaughAnalysis } from './social'
export type { MentionGraphData, MentionGraphNode, MentionGraphLink } from './social'
// 社交分析:@ 互动、关系模型、含笑量
export { getMentionAnalysis, getMentionGraph, getRelationshipGraph, getLaughAnalysis } from './social'
export type {
MentionGraphData,
MentionGraphNode,
MentionGraphLink,
RelationshipGraphData,
RelationshipGraphNode,
RelationshipGraphLink,
RelationshipGraphOptions,
} from './social'
Loading