realcoloride / node_characterai

Unofficial Character AI wrapper for node.
https://beta.character.ai/
341 stars 72 forks source link

Added creating new character #100

Closed xct007 closed 7 months ago

xct007 commented 11 months ago

This is for creating new character.

Ie test:

const CharacterAI = require("./index.js");

const characterAI = new CharacterAI();

(async () => {
    await characterAI.authenticateWithToken("Auth_token");
    const response = await characterAI.createNewCharacter({
        title: "Test Character",
        greeting: "Hello, world!",
        description: "This is a test character",
        name: "Test Character",
        visibility: "public",
    });
    console.log(response);
})();

/*
{
    status: "OK",
    character: {
        external_id: "_7AcIU5nht8GV1jdCAH7rYDtCBYoZCyrRQxtVP4jsIs",
        title: "Test Character",
        name: "Test Character",
        visibility: "PRIVATE",
        copyable: false,
        greeting: "Hello, world!",
        description: "This is a test character",
        identifier: "id:fd947f5a-e941-4795-b9ad-d2f49cdbcbed",
        avatar_file_name: "",
        songs: [],
        img_gen_enabled: false,
        base_img_prompt: "",
        img_prompt_regex: "",
        strip_img_prompt_from_msg: false,
        definition: "",
        default_voice_id: null,
        categories: [],
        user__username: "frierenDv",
        participant__name: "Test Character",
        participant__user__username: "internal_id:fd947f5a-e941-4795-b9ad-d2f49cdbcbed",
        num_interactions: 0,
        voice_id: "",
    },
}
*/
xct007 commented 11 months ago

Forget to mentions if I edited the code, removing some comments and add jsdocs in client.js

realcoloride commented 11 months ago

Good commit, will require testing and review when I'm home. I will keep you updated

EDIT: there are multiple convention violations in the code.

realcoloride commented 11 months ago

Hello as its a pretty large commit I will probably take a bit longer to review this and all the changes.

I will keep you updated.

Parking-Master commented 11 months ago

This looks great - but from some past experience it seems that @realcoloride is pretty picky with code haha.

You'll need to do what @realcoloride requests like adding back old comments, doing specific formatting, etc. Once that's done we'll test it and check if everything works right and add some recommendations.

sivertheisholt commented 11 months ago

Hi,

This looks nice! Does this also create the default chat after creation? I have noticed CAI is very buggy when it comes to the chats.

Also It looks like there was used a code formatter. Would it be an idea to include a sort of formatting configuration? For example prettier has .prettieerc. We use this a lot in projects and it's a dream to have as the format will be the same across all files and the manual work of code formatting is improved significantly.

I can open an issue if you would like to take this discussion somewhere else.

realcoloride commented 11 months ago

Hello again, I have to report a convention violation.

if ( typeof title != "string" || typeof name != "string" || typeof description != "string" || typeof greeting != "string" || typeof visibility != "string" )

using vertical conditions instead of horizontal ones, they should stay horizontal and just in general not much of the structure should have been changed (other than additions)

nstar-y commented 11 months ago

It's very good, I just tested it by fixing the existing errors and got perfect results

realcoloride commented 11 months ago

It's very good, I just tested it by fixing the existing errors and got perfect results

True, this should be kept up to date with the latest commits

realcoloride commented 11 months ago

Hello again,

Sorry but the code is filled with convention violations, this is an example:

    async createNewCharacter(options) {
        if (!this.isAuthenticated()) throw Error("You must be authenticated to do this.");
        if (options == undefined || typeof(options) != "object") throw Error("Invalid arguments.");

        let defaultOptions = {
            categories: [],
            copyable: false,
            definition: "",
            avatar_rel_path: "",
            img_gen_enabled: false,
            base_img_prompt: "",
            strip_img_prompt_from_msg: false,
            voice_id: "",
        };

        let {
            title,
            greeting,
            description,
            name,
            visibility,
        } = options;

        if (title == undefined || typeof(title) != "string") {
            throw Error("title must be a string");
        }
        if (greeting == undefined || typeof(greeting) != "string") {
            throw Error("greeting must be a string");
        }
        if (description == undefined || typeof(description) != "string") {
            throw Error("description must be a string");
        }
        if (name == undefined || typeof(name) != "string") {
            throw Error("name must be a string");
        }
        if (visibility == undefined || typeof(visibility) != "string") {
            throw Error("visibility must be a string");
        }

        visibility = visibility.toUpperCase();

        if (visibility != "PUBLIC" && visibility != "PRIVATE") throw Error("visibility must be either PUBLIC or PRIVATE");

        let optionsToUse = {
            title,
            name,
            description,
            greeting,
            description,
            name,
            visibility,
            identifier: "id:" + uuidv4(),
            // TODO: Add these options
            categories: [],
            copyable: false,
            definition: "",
            avatar_rel_path: "",
            img_gen_enabled: false,
            base_img_prompt: "",
            strip_img_prompt_from_msg: false,
            voice_id: "",
            ...defaultOptions,
        };
        const request = await this.requester.request(
            "https://beta.character.ai/chat/character/create/",
            {
                body: Parser.stringify(options),
                method: "POST",
                headers: this.getHeaders(),
            }
        );

        if (request.status() === 200) {
            const response = await Parser.parseJSON(request);
            return response;
        } else Error("Could not create character.");
    }

    // Update user details
    // for changing user profile picture, need uploadImage function; endpoint "/chat/avatar/upload/"
    async updateUserDetails(options) {
        if (!this.isAuthenticated()) throw Error("You must be authenticated to do this.");
        if (options == undefined || typeof(options) != "object") throw Error("Invalid arguments.");

        let {
            username,
            name,
        } = options;

        let _user = await this.fetchUser();

        if (username == undefined || typeof(username) != "string") {
            username = _user.user.user.username;
        }
        if (name == undefined || typeof(name) != "string") {
            name = _user.user.name;
        }

        let _options = {
            username,
            name,
            avatar_type: "UPLOADED",
            avatar_rel_path: "",
        }
        const request = await this.requester.request("https://beta.character.ai/chat/user/update/", {
            body: Parser.stringify({
                ..._options
            }),
            method: "POST",
            headers: this.getHeaders()
        });

        if (request.status() === 200) {
            const response = await Parser.parseJSON(request);

            return response;
        } else Error("Could not update user details.");
    }

This aswell. Please do not use underscores, fully name your variables and do not make the code look "vertical" and stay similar to how the other parts of the code look like.


    // trending characters
    async fetchTrendingCharacters() {
        const request = await this.requester.request("https://beta.character.ai/chat/characters/trending/", {
            headers: this.getHeaders()
        });

        if (request.status() === 200) {
            const response = await Parser.parseJSON(request);

            return response;
        } else Error("Failed fetching trending characters.");
    }

This however is much more like it. However, please use throw Error instead of else Error