realcoloride/node_characterai

Server initialization delay.

Closed this issue · 7 comments

I have made an express app using this api. But, the page load time is becoming very high. The following is my code and below that is my fix that makes the webpage load fast but breaks the functionality:

  1. CODE THAT WORKS BUT AFFECTS PAGE LOAD TIME:

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
const port = process.env.PORT || 3001;

app.use(express.static('public'));
app.use(cookieParser());
app.use(express.json());

const CharacterAI = require("node_characterai");

// Map to associate userToken with CharacterAI instances
const characterAIInstances = new Map();

// Function to generate a unique user token
function generateUserToken() {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}

// Function to create and initialize a CharacterAI instance
async function createCharacterAIInstance() {
    try {
        const characterAI = new CharacterAI();
        await characterAI.authenticateAsGuest();
        return characterAI;
    } catch (error) {
        throw error;
    }
}

app.use(async (req, res, next) => {
    const userToken = req.cookies.userToken;

    if (!userToken) {
        const newUserToken = generateUserToken();
        res.cookie('userToken', newUserToken, { maxAge: 3600000, httpOnly: true });
        req.userToken = newUserToken;
    } else {
        req.userToken = userToken;
    }

    if (!characterAIInstances.has(req.userToken)) {
        try {
            const characterAI = await createCharacterAIInstance();
            characterAIInstances.set(req.userToken, characterAI);
            req.characterAI = characterAI;
        } catch (error) {
            console.error("Error creating CharacterAI instance:", error);
            res.status(500).json({ error: "Error creating CharacterAI instance" });
            return;
        }
    } else {
        req.characterAI = characterAIInstances.get(req.userToken);
    }

    next();
});

app.post('/api/chat', async (req, res) => {
    const userMessage = req.body.message;
    const characterAI = req.characterAI;

    try {
        const characterId = "hTP85l95BwEyURXYCKMJ9WQ54eRrzsjHUr4gJG-SYng";
        const chat = await characterAI.createOrContinueChat(characterId);
        const response = await chat.sendAndAwaitResponse(userMessage, true);
        res.json({ response: response.text });
    } catch (error) {
        console.error("Error sending message to CharacterAI:", error);
        res.status(500).json({ error: "Error generating response" });
    }
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/views/index.html');
});

app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});


  1. CODE so that it initializes the characterAI instance once the message is sent but breaks functionality:

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
const port = process.env.PORT || 3001;

const CharacterAI = require("node_characterai");

// Map to associate userToken with CharacterAI instances
const characterAIInstances = new Map();

// Function to generate a unique user token
function generateUserToken() {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}

// Function to create and authenticate a CharacterAI instance
async function createAndAuthenticateCharacterAI() {
    try {
        const characterAI = new CharacterAI();
        await characterAI.authenticateAsGuest();
        return characterAI;
    } catch (error) {
        throw error;
    }
}

// Middleware: Serve static files, parse cookies, parse JSON
app.use(express.static('public'), cookieParser(), express.json());

// Middleware: User token and CharacterAI instance handling
app.use(async (req, res, next) => {
    const userToken = req.cookies.userToken;

    if (!userToken) {
        const newUserToken = generateUserToken();
        res.cookie('userToken', newUserToken, { maxAge: 3600000, httpOnly: true });
        req.userToken = newUserToken;
    } else {
        req.userToken = userToken;
    }

    if (!characterAIInstances.has(req.userToken)) {
        try {
            const characterAI = await createAndAuthenticateCharacterAI();
            characterAIInstances.set(req.userToken, characterAI);
            req.characterAI = characterAI;
        } catch (error) {
            console.error("Error creating CharacterAI instance:", error);
            res.status(500).json({ error: "Error creating CharacterAI instance" });
            return;
        }
    } else {
        req.characterAI = characterAIInstances.get(req.userToken);
    }

    next();
});

// Route: Handle chat API requests
const characterId = "hTP85l95BwEyURXYCKMJ9WQ54eRrzsjHUr4gJG-SYng";
app.post('/api/chat', async (req, res) => {
    const userMessage = req.body.message;
    const characterAI = req.characterAI;

    try {
        const chat = await characterAI.createOrContinueChat(characterId);
        const response = await chat.sendAndAwaitResponse(userMessage, true);
        res.json({ response: response.text });
    } catch (error) {
        console.error("Error sending message to CharacterAI:", error);
        res.status(500).json({ error: "Error generating response" });
    }
});

// Route: Serve index.html for the root path
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/views/index.html');
});

// Start the server
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

Any fix?

The working code also gives each user who opens from a browser a token based on cookies and thus each user can go above 10 messages while keeping chat continuation while using Authenticate As Guest!!

in

app.post('/api/chat', async (req, res) => {
    const userMessage = req.body.message;
    const characterAI = req.characterAI;

    try {
        const characterId = "hTP85l95BwEyURXYCKMJ9WQ54eRrzsjHUr4gJG-SYng";
        const chat = await characterAI.createOrContinueChat(characterId);
        const response = await chat.sendAndAwaitResponse(userMessage, true);
        res.json({ response: response.text });
    } catch (error) {
        console.error("Error sending message to CharacterAI:", error);
        res.status(500).json({ error: "Error generating response" });
    }
});

you are re creating/continuing a chat everytime a message is sent.
you need to store the chat (conversation) object and re-use it to send messages then.

Since this problem has been subject to many reocurring issues, I will point out here as an example for later similar issues:

        const chat = await characterAI.createOrContinueChat(characterId);

Creates a Conversation object, its like the equivalent of opening a conversation in the actual website.

Creating it constantly is like if you closed your browser and opened it back again to re open the same conversation EVERYTIME you wanna send a message again.

Store your chat object somewhere, and only then send a message from here

@realcoloride Is it possible to make a unique Chat for every user, unless chatID is given then continue the chat using that ID

@realcoloride Is it possible to make a unique Chat for every user, unless chatID is given then continue the chat using that ID

Thats the whole point of the chat object. See chat.js for more methods.

@realcoloride Is it possible to make a unique Chat for every user, unless chatID is given then continue the chat using that ID

Yes. In my code, it assigns each browser a token based on browser cookies and maps a unique chat instance to that token.

The "delay" should have been fixed in newer versions. Please re-open an issue if you have more problems.