brians resume | resume express chat service | resume chat program | Search

The renderHistory function retrieves and processes conversation history files from a specified project path, sorting and grouping the data by hour and identifying missing conversation summaries. It achieves this through file system operations, JSON parsing, and data grouping, but requires additional logic to be implemented for extracting time frames and creating date ranges.

Run example

npm run import -- "render history navigation"

render history navigation

const path = require('path')
const fs = require('fs')
const {ACTIVE_CONVERSATIONS, PROJECT_PATH, DEFAULT_MODEL} = importer.import("general chit chat")
const selectModel = importer.import("select llm")

async function renderHistory(req, res) {
  
  let session = req.query.session

  if(!session) {
    return ''
  }

  // TODO: extract time frame to, from prompt
  let history = fs.readdirSync(PROJECT_PATH)
  let historyFiles = []
  for(let i = 0; i < history.length; i++) {
    if(history[i].match('-' + DEFAULT_MODEL + '-' + session + '.json')) {
      historyFiles.push(path.basename(history[i]))
    }
  }

  
  // TODO: create a range of month out of the response
  let nowNearestHour = (Math.round(parseInt(Date.now()) / 60 / 60) + 1) * 60 * 60
  let includedHistory = []
  let missingSummaries = {}
  let historySummaries = ''
  historyFiles.sort((a, b) => b - a)
  for(let i = 0; i < historyFiles.length; i++) {
    let convoFile = path.join(PROJECT_PATH, historyFiles[i])
    if(fs.existsSync(convoFile)) {
      ACTIVE_CONVERSATIONS[convoFile] = JSON.parse(fs.readFileSync(convoFile))
    } else {
      ACTIVE_CONVERSATIONS[convoFile] = {}
    }

    let timestamps = Object.keys(ACTIVE_CONVERSATIONS[convoFile])
      .filter(k => k != 'summaries' && k != 'memories')
    timestamps.sort()
    for(let i = 0; i < timestamps.length; i++) {
      let nearestHourGroup = (Math.round(parseInt(timestamps[i]) / 60 / 60) + 1) * 60 * 60
      if(nearestHourGroup == nowNearestHour) {
        // TODO:
      } else if(typeof ACTIVE_CONVERSATIONS[convoFile]['summaries'] == 'undefined'
        || typeof ACTIVE_CONVERSATIONS[convoFile]['summaries'][nearestHourGroup] == 'undefined'
      ) {
        if(typeof missingSummaries[nearestHourGroup] == 'undefined') {
          missingSummaries[nearestHourGroup] = []
        }
        if(typeof ACTIVE_CONVERSATIONS[convoFile][timestamps[i]].summary == 'undefined') {
          missingSummaries[nearestHourGroup].push(ACTIVE_CONVERSATIONS[convoFile][timestamps[i]].keywords)
        } else {
          missingSummaries[nearestHourGroup].push(ACTIVE_CONVERSATIONS[convoFile][timestamps[i]].summary)
        }
      } else if(!includedHistory.includes(nearestHourGroup)) {
        includedHistory.push(nearestHourGroup)
        historySummaries += '<a onclick="loadHistory(event)" href="#history-' + nearestHourGroup + '">' 
          + ACTIVE_CONVERSATIONS[convoFile]['summaries'][nearestHourGroup] + '</div>'
      }
    }
  }

  res.send(historySummaries)


  let promptModel = await selectModel(DEFAULT_MODEL)
  let missingTimestamps = Object.keys(missingSummaries)
  //console.log(missingTimestamps)
  for(let i = 0; i < missingTimestamps.length; i++) {

    let missingDate = new Date(parseInt(missingTimestamps[i]))
    let convoFile = historyFiles.filter(f => f.startsWith(missingDate.getFullYear() 
      + '-' + String(missingDate.getMonth() + 1).padStart(2, '0')
      + '-' + DEFAULT_MODEL
      + '-'))[0]
    if(!convoFile) {
      console.error('No file for: ' + missingDate.getFullYear() 
        + '-' + String(missingDate.getMonth() + 1).padStart(2, '0'))
      continue
    } else {
      convoFile = path.join(PROJECT_PATH, convoFile)
    }

    if(typeof ACTIVE_CONVERSATIONS[convoFile]['summaries'] == 'undefined') {
      ACTIVE_CONVERSATIONS[convoFile]['summaries'] = {}
    }

    if(ACTIVE_CONVERSATIONS[convoFile]['summaries'][missingTimestamps[i]]) {
      continue
    }

    let q1 = 'Given the following statements about the conversation:\n'
      + missingSummaries[missingTimestamps[i]].join('\n')
      + '\nSummerize these points into two or three words with no title.'
    console.log('User: ' + q1)
    let a1 = await promptModel(q1)

    ACTIVE_CONVERSATIONS[convoFile]['summaries'][missingTimestamps[i]] = a1
    fs.writeFileSync(convoFile, JSON.stringify(ACTIVE_CONVERSATIONS[convoFile], null, 4))
  }


}


module.exports = renderHistory

What the code could have been:

const path = require('path');
const fs = require('fs');
const importer = require('./importer');

// Import constants and functions
const { ACTIVE_CONVERSATIONS, PROJECT_PATH, DEFAULT_MODEL } = importer.import('general chit chat');
const selectModel = importer.import('select llm');

/**
 * Render conversation history for a given session.
 * 
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function renderHistory(req, res) {
  // Get session from query parameter
  const session = req.query.session;

  // Return empty string if session is not provided
  if (!session) {
    return '';
  }

  // Get file names of conversation history
  const history = fs.readdirSync(PROJECT_PATH);
  const historyFiles = history.filter(fileName => fileName.match(`-${DEFAULT_MODEL}-${session}.json`));

  // Sort files in descending order
  historyFiles.sort((a, b) => b.localeCompare(a));

  // Get nearest hour
  const nowNearestHour = Date.now() | 0;

  // Initialize variables to store history summaries and missing summaries
  const includedHistory = [];
  const missingSummaries = {};

  // Build history summaries
  historyFiles.forEach((file) => {
    const convoFile = path.join(PROJECT_PATH, file);
    const timestamps = Object.keys(ACTIVE_CONVERSATIONS[convoFile])
     .filter((k) => k!=='summaries' && k!=='memories')
     .sort();

    timestamps.forEach((timestamp, index) => {
      const nearestHourGroup = (parseInt(timestamp) | 0) / 60 / 60 | 0 * 60 * 60;

      // Check if nearest hour group is the same as nowNearestHour
      if (nearestHourGroup === nowNearestHour) {
        return;
      }

      // Check if summaries for nearest hour group exist
      if (typeof ACTIVE_CONVERSATIONS[convoFile]['summaries'][nearestHourGroup] === 'undefined' ||
        typeof missingSummaries[nearestHourGroup] === 'undefined') {
        // Initialize missing summaries for nearest hour group
        missingSummaries[nearestHourGroup] = [];

        // Add summary to missing summaries if it exists
        if (typeof ACTIVE_CONVERSATIONS[convoFile][timestamp].summary!== 'undefined') {
          missingSummaries[nearestHourGroup].push(ACTIVE_CONVERSATIONS[convoFile][timestamp].summary);
        } else {
          missingSummaries[nearestHourGroup].push(ACTIVE_CONVERSATIONS[convoFile][timestamp].keywords);
        }
      } else if (!includedHistory.includes(nearestHourGroup)) {
        // Add nearest hour group to included history
        includedHistory.push(nearestHourGroup);

        // Build history summary
        const summary = ACTIVE_CONVERSATIONS[convoFile]['summaries'][nearestHourGroup];
        historySummaries += `<a onclick="loadHistory(event)" href="#history-${nearestHourGroup}">${summary}</a>`;
      }
    });
  });

  // Send history summaries to client
  res.send(historySummaries);

  // Get missing timestamps
  const missingTimestamps = Object.keys(missingSummaries);

  // Select model
  const promptModel = await selectModel(DEFAULT_MODEL);

  // Create summaries for missing timestamps
  missingTimestamps.forEach((timestamp) => {
    const missingDate = new Date(parseInt(timestamp));
    const convoFile = historyFiles.find((file) => file.startsWith(`${missingDate.getFullYear()}-${String(missingDate.getMonth() + 1).padStart(2, '0')}-${DEFAULT_MODEL}-`));

    if (!convoFile) {
      console.error(`No file for: ${missingDate.getFullYear()}-${String(missingDate.getMonth() + 1).padStart(2, '0')}`);
      return;
    }

    const convoFile = path.join(PROJECT_PATH, convoFile);

    // Check if summaries for missing timestamp exist
    if (typeof ACTIVE_CONVERSATIONS[convoFile]['summaries'][timestamp]!== 'undefined') {
      return;
    }

    // Build prompt
    const q1 = `Given the following statements about the conversation:\n${missingSummaries[timestamp].join('\n')}\nSummarize these points into two or three words with no title.`;
    console.log(`User: ${q1}`);

    // Get response from model
    const a1 = promptModel(q1);

    // Update summaries
    ACTIVE_CONVERSATIONS[convoFile]['summaries'][timestamp] = a1;
    fs.writeFileSync(convoFile, JSON.stringify(ACTIVE_CONVERSATIONS[convoFile], null, 4));
  });
}

module.exports = renderHistory;

Code Breakdown: renderHistory Function

Dependencies and Variables

Function Purpose

The renderHistory function is designed to retrieve and process conversation history files from a specified project path.

Code Logic

  1. Checks if a session query parameter is present in the request, and returns an empty string if it's not.
  2. Uses the fs module to read the project directory and extract file names that match a specific pattern (e.g., -<model>-<session>.json).
  3. Sorts the file names in descending order (newest files first).
  4. Iterates through the file names, reading each file and parsing its contents as JSON.
  5. Extracts conversation timestamps from each file and groups them by hour.
  6. Checks if summaries are missing for a specific hour group and adds the missing conversation data to a missingSummaries object.

TODOs and Missing Logic

Variables and Objects