( db: DatabaseAdapter, gapThreshold: number = DEFAULT_SESSION_GAP_THRESHOLD, onProgress?: (current: number, total: number) => void )
| 586 | * @returns number of sessions created |
| 587 | */ |
| 588 | export function generateSessionIndex( |
| 589 | db: DatabaseAdapter, |
| 590 | gapThreshold: number = DEFAULT_SESSION_GAP_THRESHOLD, |
| 591 | onProgress?: (current: number, total: number) => void |
| 592 | ): number { |
| 593 | const countRow = db.prepare('SELECT COUNT(*) as count FROM message').get() as { count: number } | undefined |
| 594 | if (!countRow || countRow.count === 0) return 0 |
| 595 | |
| 596 | const sessionMarkSQL = ` |
| 597 | WITH message_ordered AS ( |
| 598 | SELECT id, ts, LAG(ts) OVER (ORDER BY ts, id) AS prev_ts FROM message |
| 599 | ), |
| 600 | session_marks AS ( |
| 601 | SELECT id, ts, |
| 602 | CASE WHEN prev_ts IS NULL OR (ts - prev_ts) > ? THEN 1 ELSE 0 END AS is_new_session |
| 603 | FROM message_ordered |
| 604 | ), |
| 605 | session_ids AS ( |
| 606 | SELECT id, ts, SUM(is_new_session) OVER (ORDER BY ts, id) AS session_num |
| 607 | FROM session_marks |
| 608 | ) |
| 609 | SELECT id, ts, session_num FROM session_ids |
| 610 | ` |
| 611 | |
| 612 | const messages = db.prepare(sessionMarkSQL).all(gapThreshold) as Array<{ |
| 613 | id: number |
| 614 | ts: number |
| 615 | session_num: number |
| 616 | }> |
| 617 | |
| 618 | if (messages.length === 0) return 0 |
| 619 | |
| 620 | const sessionMap = new Map<number, { startTs: number; endTs: number; messageIds: number[] }>() |
| 621 | for (const msg of messages) { |
| 622 | const session = sessionMap.get(msg.session_num) |
| 623 | if (!session) { |
| 624 | sessionMap.set(msg.session_num, { startTs: msg.ts, endTs: msg.ts, messageIds: [msg.id] }) |
| 625 | } else { |
| 626 | session.endTs = msg.ts |
| 627 | session.messageIds.push(msg.id) |
| 628 | } |
| 629 | } |
| 630 | |
| 631 | const insertSession = db.prepare( |
| 632 | 'INSERT INTO segment (start_ts, end_ts, message_count, is_manual, summary) VALUES (?, ?, ?, 0, NULL)' |
| 633 | ) |
| 634 | const insertContext = db.prepare('INSERT INTO message_context (message_id, segment_id, topic_id) VALUES (?, ?, NULL)') |
| 635 | |
| 636 | return db.transaction(() => { |
| 637 | clearSessionIndexRows(db) |
| 638 | |
| 639 | let processed = 0 |
| 640 | const total = sessionMap.size |
| 641 | for (const [, data] of sessionMap) { |
| 642 | const result = insertSession.run(data.startTs, data.endTs, data.messageIds.length) |
| 643 | const newId = (result.lastInsertRowid ?? 0) as number |
| 644 | for (const mid of data.messageIds) { |
| 645 | insertContext.run(mid, newId) |
no test coverage detected