char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
3dc7285b4
char/aliceai-t5-moe
1import { NEWLINE } from '$lib/constants' ; 2import { MessageRole , MessageType } from '$lib/enums' ; 3import { ConversationTransferService } from '$lib/services/conversation-transfer.service' ; 4import type { ExportedConversation } from '$lib/types/database' ; 5import { strToU8 , zipSync } from 'fflate' ; 6import { describe , expect , it } from 'vitest' ; 7 8function makeSession ( id :string ) :ExportedConversation { 9return { 10conv :{ currNode :` ${ id } -msg` , id, lastModified :0 , name :`Chat ${ id } ` }, 11messages :[ 12{ 13children :[], 14content :`hello from ${ id } ` , 15convId :id , 16id :` ${ id } -msg` , 17parent :null , 18role :MessageRole . USER , 19timestamp :0 , 20type :MessageType . TEXT 21} 22] 23} as unknown as ExportedConversation ; 24} 25 26/** 27* `parseImportFile` detects the format from the file contents. iOS has no UTI 28* for `.jsonl`, so the picker cannot filter on it and the filename carries no 29* guarantee: a JSONL export must import under any name. 30*/ 31describe ( 'ConversationTransferService.parseImportFile' , () => { 32it ( 'imports a JSONL export whose name has no meaningful extension' , async () => { 33const jsonl = ConversationTransferService . serializeSessionToJsonl ( makeSession ( 'a' )); 34const sessions = await ConversationTransferService . parseImportFile ( new File ([ jsonl ], 'export' )); 35 36expect ( sessions ). toHaveLength ( 1 ); 37expect ( sessions [ 0 ]. conv . id ). toBe ( 'a' ); 38expect ( sessions [ 0 ]. messages [ 0 ]. content ). toBe ( 'hello from a' ); 39}); 40 41it ( 'imports several sessions from one JSONL file' , async () => { 42const jsonl = [ makeSession ( 'a' ), makeSession ( 'b' )] 43. map (( session ) => ConversationTransferService . serializeSessionToJsonl ( session )) 44. join ( NEWLINE ); 45const sessions = await ConversationTransferService . parseImportFile ( 46new File ([ jsonl ], 'export.txt' ) 47); 48 49expect ( sessions . map (( session ) => session . conv . id )). toEqual ([ 'a' , 'b' ]); 50}); 51 52it ( 'imports a ZIP archive whose name has no meaningful extension' , async () => { 53const zipped = zipSync ({ 54'a.jsonl' :strToU8 ( ConversationTransferService . serializeSessionToJsonl ( makeSession ( 'a' ))), 55'b.jsonl' :strToU8 ( ConversationTransferService . serializeSessionToJsonl ( makeSession ( 'b' ))), 56'notes.txt' :strToU8 ( 'ignored' ) 57}); 58const sessions = await ConversationTransferService . parseImportFile ( 59new File ([ zipped ], 'archive' ) 60); 61 62expect ( sessions . map (( session ) => session . conv . id ). sort ()). toEqual ([ 'a' , 'b' ]); 63}); 64 65it ( 'imports the legacy JSON array format' , async () => { 66const json = JSON . stringify ([ makeSession ( 'a' )], null , 2 ); 67const sessions = await ConversationTransferService . parseImportFile ( 68new File ([ json ], 'export.jsonl' ) 69); 70 71expect ( sessions ). toHaveLength ( 1 ); 72expect ( sessions [ 0 ]. conv . id ). toBe ( 'a' ); 73}); 74 75it ( 'imports the legacy JSON single object format' , async () => { 76const json = JSON . stringify ( makeSession ( 'a' )); 77const sessions = await ConversationTransferService . parseImportFile ( new File ([ json ], 'export' )); 78 79expect ( sessions ). toHaveLength ( 1 ); 80expect ( sessions [ 0 ]. conv . id ). toBe ( 'a' ); 81}); 82 83it ( 'rejects a file that holds neither format' , async () => { 84await expect ( 85ConversationTransferService . parseImportFile ( new File ([ 'not an export' ], 'export.jsonl' )) 86). rejects . toThrow (); 87}); 88});