Building Conversational AI with Context Memory in Node.js

Building a conversational AI with memory requires careful context management:

class ConversationManager {
  constructor(options = {}) {
    this.maxTokens = options.maxTokens || 4000;
    this.systemPrompt = options.systemPrompt || 'You are a helpful assistant.';
    this.conversations = new Map();
  }

  getHistory(sessionId) {
    if (!this.conversations.has(sessionId)) {
      this.conversations.set(sessionId, []);
    }
    return this.conversations.get(sessionId);
  }

  async chat(sessionId, userMessage) {
    const history = this.getHistory(sessionId);
    history.push({ role: 'user', content: userMessage });

    // Trim history if too long
    while (this.estimateTokens(history) > this.maxTokens) {
      history.shift();
    }

    const response = await openai.chat.completions.create({
      model: 'gpt-4',
      messages: [
        { role: 'system', content: this.systemPrompt },
        ...history
      ]
    });

    const reply = response.choices[0].message.content;
    history.push({ role: 'assistant', content: reply });
    return reply;
  }

  estimateTokens(messages) {
    return messages.reduce((sum, m) => sum + m.content.length / 4, 0);
  }
}

Async waterfall example nodejs

To avoid callback hell , a very useful tool for structuring calls in a sequence and make sure the steps pass the data to the next step.

var async = require('async');

async.waterfall(
    [
        function(callback) {
            callback(null, 'Yes', 'it');
        },
        function(arg1, arg2, callback) {
            var caption = arg1 +' and '+ arg2;
            callback(null, caption);
        },
        function(caption, callback) {
            caption += ' works!';
            callback(null, caption);
        }
    ],
    function (err, caption) {
        console.log(caption);
        // Node.js and JavaScript Rock!
    }
);

nJoy 😉

Node.js Start script or run command and handoff to OS (no waiting)

Sometimes you want to run something in the OS from your node code but you do not want to follow it or have a callback posted on your stack. The default for child_process spawning is to hold on to a handle and park a callback on the stack. however there is an option which is called detached.

var spawn = require('child_process').spawn;
spawn('/usr/scripts/script.sh', ['param1'], {
    detached: true
});

You can even setup the environment of the call to add stdio and stderr pipes to the call and connect them to OS fs descriptors like this:

var fs = require('fs'),
    spawn = require('child_process').spawn,
    out = fs.openSync('./out.log', 'a'),
    err = fs.openSync('./err.log', 'a');

spawn('/usr/scripts/script.sh', ['param1'], {
    stdio: [ 'ignore', out, err ], // piping stdout and stderr to out.log
    detached: true
}).unref();

The unref disconnects the process. from the parent it equates to a disown in shell.

Thanks to O/P : https://stackoverflow.com/questions/25323703/nodejs-execute-command-in-background-and-forget

Also Ref: https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

and

https://github.com/nodejs/node-v0.x-archive/issues/9255

nJoy 😉

Dummy node script to respond 200 (or anything) to a call for testing purposes

This is as bare a node App as you can make but it comes in handy when you want a . dummy server just to return 200s and or a JSON object at super fast speeds on small systems:

 

var express = require('express');

var app     = express();


app.get('*', function(req, res) {
    res.sendStatus(200);
});

app.listen('3000');

console.log('Magic happens on port 3000');

exports = module.exports = app;


Before running the js file run 
npm install express 

to deploy express..

Thats it !

nJoy 😉

Installing node on old version of Ubuntu 10.04

 curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash

logoff and log on

nvm ls-remote
nvm install v7.9.0
npm -v
node -v

Caveat :   Lots of node stuff fails to compile and run on such an old version of linux be warned…
Thats it you now have node and npm installed. nJoy 😉

Saving a million documents in Mongo using Nodejs and mongodb module

/**
* Created by davidsaliba on 13/03/2017.
*/
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;

var url = 'mongodb://localhost:27017/test';
var async = require ('async');

var entry = {
data : "skdlfjsdf",
array : [ {id:"arr_obj1"} , {id:"arr_obj2"} ]
};

var entries = [];

var total_entries = 1000000

for (var j = 0 ; j <= total_entries ; j ++){
console.log (j);
entries.push({"_id":j ,entry:entry});
}

console.log ("Number of entries", entries.length);

MongoClient.connect(url, function(err, db) {
// Get the collection
var col = db.collection('articles');
//

var bulk = col.initializeOrderedBulkOp();
var counter = 0;

async.whilst(
// Iterator condition
function() { return counter < total_entries },

// Do this in the iterator
function(callback) {
counter++;

bulk.insert(entries[counter] );

if ( counter % 1000 == 0 ) {
bulk.execute(function(err,result) {
bulk = col.initializeOrderedBulkOp();
callback(err);
});
} else {
callback();
}
},

// When all is done
function(err) {
if ( counter % 1000 != 0 )
bulk.execute(function(err,result) {
console.log( "inserted some more" );
});
console.log( "I'm finished now" );
db.close();
}
);
});

nJoy 😉

Install node.js on Centos 6.8

Epel’s yum install does not cut it anymore at time of writing installing node.js causes a mass of 404s and file not found.

 

current best approach :

Enterprise Linux and Fedora

Including Red Hat® Enterprise Linux® / RHEL, CentOS and Fedora.

Node.js is available from the NodeSource Enterprise Linux and Fedora binary distributions repository. Support for this repository, along with its scripts, can be found on GitHub at nodesource/distributions.

Note that the Node.js packages for EL 5 (RHEL5 and CentOS 5) depend on the EPEL repository being available. The setup script will check and provide instructions if it is not installed.

Run as root on RHEL, CentOS or Fedora, for Node.js v4 LTS Argon:

curl --silent --location https://rpm.nodesource.com/setup_4.x | bash -

Alternatively for Node.js v5:

curl --silent --location https://rpm.nodesource.com/setup_5.x | bash -

Alternatively for Node.js 0.10:

curl --silent --location https://rpm.nodesource.com/setup | bash -

Then install, as root:

yum -y install nodejs

Optional: install build tools

To compile and install native addons from npm you may also need to install build tools:

yum install gcc-c++ make
# or: yum groupinstall 'Development Tools'

Available architectures:

  • i386 (32-bit, not available for EL7)
  • x86_64 (64-bit)

Supported Red Hat® Enterprise Linux® versions:

  • RHEL 5 (32-bit and 64-bit)
  • RHEL 6 (32-bit and 64-bit)
  • RHEL 7 (64-bit)

Supported CentOS versions:

  • CentOS 5 (32-bit and 64-bit)
  • CentOS 6 (32-bit and 64-bit)
  • CentOS 7 (64-bit)

Supported CloudLinux versions:

  • CloudLinux 6 (32-bit and 64-bit)

Supported Fedora versions:

  • Fedora 21 (Twenty One) (32-bit and 64-bit)
  • Fedora 20 (Heisenbug) (32-bit and 64-bit)
  • Fedora 19 (Schrödinger’s Cat) (32-bit and 64-bit)

Other distributions known to be supported:

  • Oracle Linux (mirrors RHEL very closely)
  • Amazon Linux (tested on 2014.03)

nJoy 😉

 

Installing node on Fedora 22

yum install gcc-c++ make openssl-devel

 

  • Install from Source code :
    wget http://nodejs.org/dist/v0.8.15/node-v0.8.15.tar.gz
    tar zxvf node-v0.8.15.tar.gz
    cd node-v0.8.15
    ./configure
    make
    make install
  • Install from GIT repository
    yum install git
    git clone git://github.com/joyent/node.git
    cd node
    ./configure
    make
    make install

 

nJoy 😉

 

package.json sample

This is the basic structure for a node.js package file

{
"name": "Express-Basic",
"description": "Demonstrating Express",
"version": "0.0.1",
"private": true,
"dependencies": {
"express": "3.x"
}
}

nJoy 😉

Node.js and Express with HTTPS

Quoting from the doco + some missing stuff:

var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
var fs = require('fs');

var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

http.createServer(app).listen(80);
https.createServer(options, app).listen(443);

nJoy 😉