const BASE_URL = "https://api.axonbox.net"; const LOGIN_EMAIL = "support@axonbox.net"; import { readFile } from 'fs/promises'; const Imap = require( 'imap' ); const messages = [ { role: "user", content: "can you write 3 sorting algorithms for arrays of strings in c?", timestamp: new Date( ).toISOString( ) }, { role: "user", content: "can you modify that to be for an array of floats?", timestamp: new Date( ).toISOString( ) }, { role: "user", content: "what are the fastest sorting algorithms?", timestamp: new Date( ).toISOString( ) } ]; function getUrl( endpoint_name: string ): string { return `${ BASE_URL }${ endpoint_name }`; } function getRandomIndex( length: number ): number { return Math.floor( Math.random( ) * length ); } async function logErrorResponse( res: Response ): Promise { console.error( await res.json( ) ); return false; } async function apiCall( endpoint: string, method: string, payload: object = { } ) { return await fetch( getUrl( endpoint ), { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify( payload ) } ); } async function searchAndFetchNewEmail( mail: any ): Promise { return new Promise( ( resolve, reject ) => { let retries = 4; function attemptSearch( ) { mail.search( [ 'UNSEEN' ], ( err, results ) => { if ( err ) return reject( err ); if ( !results.length ) { if ( retries > 0 ) { --retries; console.log( `No unseen emails yet. Retrying in 25 seconds ( ${retries} retries left )...` ); setTimeout( attemptSearch, 25000 ); } else { mail.end( ); return reject( new Error( 'no unread emails after 100 seconds' ) ); } return; } const latest_email = results[ results.length - 1 ]; const f = mail.fetch( latest_email, { bodies: "" } ); let body = ""; f.on( "message", msg => { msg.on( "body", ( stream, info ) => { stream.on( "data", ( chunk ) => { body += chunk.toString( 'utf8' ); }); }); msg.on( 'end', ( ) => { } ); }); f.on( 'end', ( ) => { mail.end( ); resolve( body ); }); f.on( 'error', ( fetcherr ) => { mail.end( ); reject( fetcherr ); }); }); } attemptSearch( ); }); } async function getNewEmailBody( mail: any ): Promise { return new Promise( ( resolve, reject ) => { const timeout = setTimeout( ( ) => { mail.end( ); reject( new Error( 'Timeout waiting for email connection' ) ); }, 180000 ); mail.once( "ready", ( ) => { mail.openBox( "INBOX", false, ( err, mailbox ) => { if ( err ) { clearTimeout( timeout ); mail.end( ); return reject( err ); } mail.on( "mail", async ( ) => { try { let emailBody = await searchAndFetchNewEmail( mail ); clearTimeout( timeout ); resolve( emailBody ); } catch( e ) { clearTimeout( timeout ); mail.end( ); reject( e ); } }); }); }); mail.once( "error", ( err ) => { clearTimeout( timeout ); reject( err ); }); mail.connect( ); }); } async function getSiteToken( ) { const password: string = ( await readFile( './data/mail_password.txt', 'utf8' ) ).trim( ); console.log( `\n\nsigning into email with ${ LOGIN_EMAIL }:${ password }\n\n` ); let mail = new Imap({ user: LOGIN_EMAIL, password, host: "imappro.zoho.com", port: 993, tls: true }); let email_body: string = ""; try { const result = await getNewEmailBody( mail ); if ( typeof result !== "string" ) throw new Error( "invalid email body" ); email_body = result; } catch ( err ) { console.error( "failed to fetch email: ", err ); return null; } const login_token: string = email_body.split( "?token=" )[ 1 ]; if ( !login_token ) { console.log( `failed to find token in ${ email_body }` ); return null; } const login_res = await fetch( getUrl( `/login?token=${ login_token }` ), { method: "GET" } ); if ( !login_res.ok ) { console.error( "login request failed" ); await logErrorResponse( login_res ); return null; } const login_data = await login_res.json( ); return login_data.session; } const delay = ( ms: number ) => new Promise( r => setTimeout( r, ms ) ); const endpoints = { "/get-tokens": async ( token: string ) => await apiCall( "/get-tokens", "POST", { token } ), "/create-token": async ( token: string ) => await apiCall( "/create-token", "POST", { token } ), "/delete-token": async ( token: string, id: number ) => await apiCall( "/delete-token", "POST", { token, id } ), "/delete-tokens": async ( token: string ) => await apiCall( "/delete-tokens", "POST", { token } ), "/send-login-link": async ( ) => await apiCall( "/send-login-link", "POST", { email: `${ LOGIN_EMAIL }` } ), "/invalidate-session": async ( token: string ) => await apiCall( "/invalidate-session", "POST", { token } ), "/invalidate-all-sessions": async ( token: string ) => await apiCall( "/invalidate-all-sessions", "POST", { token } ), "/settings": async ( token: string ) => await apiCall( "/settings", "POST", { token } ), "/get-notes": async ( token: string ) => await apiCall( "/get-notes", "POST", { token } ), "/getalldata": async ( token: string ) => await apiCall( "/getalldata", "POST", { token } ), "/delete-note": async ( token: string, noteId: string ) => await apiCall( "/delete-note", "POST", { token, noteId } ), "/delete-notes": async ( token: string ) => await apiCall( "/delete-notes", "POST", { token } ), "/models": async ( ) => await apiCall( "/models", "POST" ), "/get-chat": async ( token: string, chatId: string ) => await apiCall( "/get-chat", "POST", { token, chatId } ), "/create-chat": async ( token: string ) => await apiCall( "/create-chat", "POST", { token } ), "/generate": async ( token: string, model: string, prompt: string = "write fibonacci in c99 please" ) => await apiCall( "/generate", "POST", { token, model, prompt, suffix: "" } ), "/delete-chat": async ( token: string, chatId: string ) => await apiCall( "/delete-chat", "POST", { token, chatId } ), "/update-settings": async ( token: string, free: boolean, models: any[ ] ) => { const available_models = models.filter( ( m ) => m.free === ( free ? 1 : 0 ) ); return await apiCall( "/update-settings", "POST", { token, prefs: { nickname: ( Math.floor( Math.random( ) * 90000000 ) + 10000000 ).toString( ), prompt_data: { system: "explain everything to me like i am " + getRandomIndex( 100 ).toString( ) + " years old.", }, site_prefs: { model: available_models[ getRandomIndex( available_models.length ) ].name, }, }, }); }, "/chat": async ( token: string, chatfile: string, system: string, model: string, message: any ) => await apiCall( "/chat", "POST", { token, model, chatfile, system, options: { seed: 123, temperature: 0.5 }, messages: [ message ] }) }; async function test( ): Promise { let login_link_res = await endpoints[ "/send-login-link" ]( ); if ( !login_link_res.ok ) return await logErrorResponse( login_link_res ); else console.log( `sent login url to: '${ LOGIN_EMAIL }'!` ); let site_token = await getSiteToken( ) || ""; if ( !site_token ) { console.log( "failed to get site tokens", site_token ); return false; } let settings_res = await endpoints[ "/settings" ]( site_token ); if ( !settings_res.ok ) return await logErrorResponse( settings_res ); const models_res = await endpoints[ "/models" ]( ); if ( !models_res.ok ) return await logErrorResponse( models_res ); const models = await models_res.json( ); console.log( "\ngot models: " ); models.models.forEach( m => console.log( m.name ) ); console.log( "\n" ); let settings = await settings_res.json( ); console.log( settings ); console.log( "\n" ); const is_free_tier: boolean = settings.userprefs.plan.endTime <= Date.now( ); const update_settings_res = await endpoints[ "/update-settings" ]( site_token, is_free_tier, models.models ); if ( !update_settings_res.ok ) return await logErrorResponse( update_settings_res ); settings_res = await endpoints[ "/settings" ]( site_token ); if ( !settings_res.ok ) return await logErrorResponse( settings_res ); settings = await settings_res.json( ); console.log( "updated settings: " ); console.log( settings ); console.log( "\n" ); let get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); if ( !get_tokens_res.ok ) return await logErrorResponse( get_tokens_res ); console.log( "tokens:", await get_tokens_res.json( ) ); let create_token_res = await endpoints[ "/create-token" ]( site_token ); if ( !create_token_res.ok ) return await logErrorResponse( create_token_res ); let create_token_res_json = await create_token_res.json( ); let new_token = create_token_res_json.token; console.log( "\ncreated new token: " + new_token + '\n' ); get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); if ( !get_tokens_res.ok ) return await logErrorResponse( get_tokens_res ); let tokens_res_json = await get_tokens_res.json( ); console.log( "tokens:", tokens_res_json ); const generate_res = await endpoints[ "/generate" ]( new_token, settings.userprefs.site_prefs.model ); if ( !generate_res.ok ) return await logErrorResponse( generate_res ); console.log( "generated:", await generate_res.text( ) ); const create_chat_res = await endpoints[ "/create-chat" ]( site_token ); if ( !create_chat_res.ok ) return await logErrorResponse( create_chat_res ); const create_chat_res_json = await create_chat_res.json( ); const chat_id = create_chat_res_json.chatId; // TODO : fix this so messages are sent back to model properly // WARNING : this will break in the future when backend behaves as expected, managing message storage by itself for ( let idx = 0; idx < messages.length; ++idx ) { const chat_res = await endpoints[ "/chat" ]( new_token, chat_id, settings.userprefs.prompt_data.system, settings.userprefs.site_prefs.model, { role: messages[ idx ].role, content: messages[ idx ].content, timestamp: new Date( ).toISOString( ) } ); if ( !chat_res.ok ) return await logErrorResponse( chat_res ); const chat_res_text = await chat_res.text( ); const chunks = chat_res_text.split( "\n" ); const last = chunks[ chunks.length - 2 ]; console.log( "chat response: ", last ); await delay( 1000 ); } const get_chat_res = await endpoints[ "/get-chat" ]( site_token, chat_id ); if ( !get_chat_res.ok ) return await logErrorResponse( get_chat_res ); const get_chat_res_json = await get_chat_res.json( ); console.log( `\nchat id: ${ chat_id }` ); console.log( `chat name: ${ get_chat_res_json.name }` ); console.log( `chat contents: ${ await get_chat_res_json.contents }` ); const delete_chat_res = await endpoints[ "/delete-chat" ]( site_token, chat_id ); if ( !delete_chat_res.ok ) return await logErrorResponse( delete_chat_res ); console.log( `\nchat ${ chat_id } deleted` ); let get_notes_res = await endpoints[ "/get-notes" ]( site_token ); if ( !get_notes_res.ok ) return await logErrorResponse( get_notes_res ); let get_notes_res_json = await get_notes_res.json( ); console.log( "found notes:", get_notes_res_json ); if ( get_notes_res_json.notes.length > 1 ) { const random_note = get_notes_res_json.notes[ getRandomIndex( get_notes_res_json.notes.length ) ]; const delete_note_res = await endpoints[ "/delete-note" ]( site_token, random_note.id ); if ( !delete_note_res.ok ) return await logErrorResponse( delete_note_res ); console.log( `deleted note[ ${ random_note.id } ]: ${ random_note.content }` ); get_notes_res = await endpoints[ "/get-notes" ]( site_token ); if ( !get_notes_res.ok ) return await logErrorResponse( get_notes_res ); get_notes_res_json = await get_notes_res.json( ); console.log( "found notes:", get_notes_res_json ); if ( get_notes_res_json.notes.length > 2 ) { const delete_notes_res = await endpoints[ "/delete-notes" ]( site_token ); if ( !delete_notes_res.ok ) return await logErrorResponse( delete_notes_res ); console.log( "deleted all notes:", await delete_notes_res.json( ) ); } get_notes_res = await endpoints[ "/get-notes" ]( site_token ); if ( !get_notes_res.ok ) return await logErrorResponse( get_notes_res ); get_notes_res_json = await get_notes_res.json( ); console.log( "found notes:", get_notes_res_json ); } else console.log( "0 ( zero ) notes to delete, skipping step" ); const token_idx = getRandomIndex( tokens_res_json.tokens.length ); if ( !!tokens_res_json.tokens.length ) { const delete_token_res = await endpoints[ "/delete-token" ]( site_token, token_idx ); if ( !delete_token_res.ok ) return await logErrorResponse( delete_token_res ); console.log( "deleted token: ", await delete_token_res.json( ) ); try { const chat_res = await endpoints[ "/chat" ]( new_token, chat_id, settings.userprefs.prompt_data.system, settings.userprefs.site_prefs.model, messages[ 0 ] ); if ( chat_res.ok ) return await logErrorResponse( chat_res ); } catch ( error ) { console.log( "chat with deleted token failed as expected" ); } get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); if ( !get_tokens_res.ok ) return await logErrorResponse( get_tokens_res ); console.log( "remaining tokens:", await get_tokens_res.json( ) ); } else console.log( `failed to find token ${ new_token }` ); if ( tokens_res_json.tokens.length > 1 ) { const delete_tokens_res = await endpoints[ "/delete-tokens" ]( site_token ); if ( !delete_tokens_res.ok ) return await logErrorResponse( delete_tokens_res ); console.log( "deleted all tokens: ", await delete_tokens_res.json( ) ); get_tokens_res = await endpoints[ "/get-tokens" ]( site_token ); if ( !get_tokens_res.ok ) return await logErrorResponse( get_tokens_res ); console.log( "remaining tokens:", await get_tokens_res.json( ) ); } else console.log( `'${ tokens_res_json.tokens.length - 1 }' tokens, not enough to delete` ); const getalldata_res = await endpoints[ "/getalldata" ]( site_token ); if ( !getalldata_res.ok ) return await logErrorResponse( getalldata_res ); console.log( `getalldata returned: ${ getalldata_res.headers.get( 'Content-Length' ) } bytes of data` ); create_token_res = await endpoints[ "/create-token" ]( site_token ); if ( !create_token_res.ok ) return await logErrorResponse( create_token_res ); create_token_res_json = await create_token_res.json( ); new_token = create_token_res_json.token; console.log( "\ncreated new token: " + new_token + '\n' ); const invalidate_session_res = await endpoints[ "/invalidate-session" ]( site_token ); if ( !invalidate_session_res.ok ) return await logErrorResponse( invalidate_session_res ); console.log( "invalidated session: ", await invalidate_session_res.json( ) ); settings_res = await endpoints[ "/settings" ]( site_token ); if ( settings_res.ok ) return await logErrorResponse( settings_res ); login_link_res = await endpoints[ "/send-login-link" ]( ); if ( !login_link_res.ok ) return await logErrorResponse( login_link_res ); else console.log( `sent login url to: '${ LOGIN_EMAIL }'!` ); site_token = await getSiteToken( ) || ""; if ( !site_token ) { console.log( "failed to get post-login token", site_token ); return false; } const invalidate_all_sessions_res = await endpoints[ "/invalidate-all-sessions" ]( site_token ); if ( !invalidate_all_sessions_res.ok ) return await logErrorResponse( invalidate_all_sessions_res ); console.log( "invalidated all sessions: ", await invalidate_all_sessions_res.json( ) ); settings_res = await endpoints[ "/settings" ]( "site_token" ); if ( settings_res.ok ) return await logErrorResponse( settings_res ); return true; } ( async function( ) { if ( !await test( ) ) console.error( "tests failed\n" ); else console.log( "tests passed\n" ); } ) ( );