char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
3dc7285b4
char/aliceai-t5-moe
1/** 2* Utility functions for conversation data manipulation 3*/ 4import { MessageRole } from '$lib/enums' ; 5import type { DatabaseMessage } from '$lib/types' ; 6 7/** 8* Model that generated the conversation's latest assistant message, or null 9* when no assistant message carries one. 10*/ 11export function getConversationModel ( messages :readonly DatabaseMessage []) :string | null { 12for ( let i = messages . length - 1 ; i >= 0 ; i -- ) { 13const message = messages [ i ]; 14 15if ( message . role === MessageRole . ASSISTANT && message . model ) return message . model ; 16} 17 18return null ; 19} 20 21/** 22* Creates a map of conversation IDs to their message counts from exported conversation data 23* @param exportedData - Array of exported conversations with their messages 24* @returns Map of conversation ID to message count 25*/ 26export function createMessageCountMap ( 27exportedData :Array <{ conv :DatabaseConversation ; messages :DatabaseMessage [] }> 28) :Map < string , number > { 29const countMap = new Map < string , number >(); 30 31for ( const item of exportedData ) { 32countMap . set ( item . conv . id , item . messages . length ); 33} 34 35return countMap ; 36} 37 38/** 39* Gets the message count for a specific conversation from the count map 40* @param conversationId - The ID of the conversation 41* @param countMap - Map of conversation IDs to message counts 42* @returns The message count, or 0 if not found 43*/ 44export function getMessageCount ( conversationId :string , countMap :Map < string , number >) :number { 45return countMap . get ( conversationId ) ?? 0 ; 46} 47 48export interface ConversationTreeItem { 49conversation :DatabaseConversation ; 50depth :number ; 51} 52 53// Pinned conversations first, then by lastModified descending 54const comparePinnedThenRecent = ( a :DatabaseConversation , b :DatabaseConversation ) => { 55if ( a . pinned && ! b . pinned ) return - 1 ; 56 57if ( ! a . pinned && b . pinned ) return 1 ; 58 59return b . lastModified - a . lastModified ; 60}; 61 62/** 63* Builds a flat tree of conversations with depth levels for nested forks. 64* Accepts a pre-filtered list so search filtering stays in the component. 65* 66* Output order matches the sidebar render exactly: pinned first, then 67* unpinned by lastModified desc, with forks interleaved under their parents. 68* Range-select / marquee in the sidebar rely on this alignment. 69*/ 70export function buildConversationTree ( convs :DatabaseConversation []) :ConversationTreeItem [] { 71const childrenByParent = new Map < string , DatabaseConversation []>(); 72const forkIds = new Set < string >(); 73 74for ( const conv of convs ) { 75if ( conv . forkedFromConversationId ) { 76forkIds . add ( conv . id ); 77 78const siblings = childrenByParent . get ( conv . forkedFromConversationId ) || []; 79 80siblings . push ( conv ); 81childrenByParent . set ( conv . forkedFromConversationId , siblings ); 82} 83} 84 85const result :ConversationTreeItem [] = []; 86const visited = new Set < string >(); 87 88function walk ( conv :DatabaseConversation , depth :number ) { 89visited . add ( conv . id ); 90result . push ({ conversation :conv , depth}); 91 92const children = childrenByParent . get ( conv . id ); 93 94if ( children ) { 95children . sort ( comparePinnedThenRecent ); 96 97for ( const child of children ) { 98walk ( child , depth + 1 ); 99} 100} 101} 102 103const roots = convs . filter (( c ) => ! forkIds . has ( c . id )). sort ( comparePinnedThenRecent ); 104 105for ( const root of roots ) { 106walk ( root , 0 ); 107} 108 109for ( const conv of convs ) { 110if ( ! visited . has ( conv . id )) { 111walk ( conv , 1 ); 112} 113} 114 115return result ; 116}