Skip to content

grokit for node.js #1

@Maxhem2

Description

@Maxhem2

Thanks for the work EveripediaNetwork! For anyone who needs this really well working script but as nodejs. Maybe you can open a repo for nodejs as well EveripediaNetwork?

//grokit.js
const { EventEmitter } = require('events');

const GrokModels = Object.freeze({
    GROK_2: 'grok-2',
    GROK_2_MINI: 'grok-2-mini',
});

class Grokit {
    static BEARER_TOKEN = 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';

    /**
     * Initializes the Grokit instance.
     * @param {Object} options
     * @param {string} options.auth_token - Authentication token.
     * @param {string} options.csrf_token - CSRF token.
     */
    constructor({ auth_token = process.env.X_AUTH_TOKEN, csrf_token = process.env.X_CSRF_TOKEN } = {}) {
        this.auth_token = auth_token;
        this.csrf_token = csrf_token;
        this._validateTokens();
        this.cookie = this._createCookie();
        this.headers = this._createHeaders();
    }

    _validateTokens() {
        if (!this.auth_token || !this.csrf_token) {
            throw new Error('X_AUTH_TOKEN and X_CSRF_TOKEN must be provided');
        }
    }

    _createCookie() {
        return `auth_token=${this.auth_token}; ct0=${this.csrf_token};`;
    }

    _createHeaders() {
        return {
            'X-Csrf-Token': this.csrf_token,
            'Authorization': `Bearer ${Grokit.BEARER_TOKEN}`,
            'Content-Type': 'application/json',
            'Cookie': this.cookie,
        };
    }

    async createConversation() {
        const url = 'https://x.com/i/api/graphql/UBIjqHqsA5aixuibXTBheQ/CreateGrokConversation';
        const payload = {
            variables: {},
            queryId: 'UBIjqHqsA5aixuibXTBheQ',
        };

        const response = await this._makeRequest(url, payload);
        if (response && response.data && response.data.create_grok_conversation) {
            return response.data.create_grok_conversation.conversation_id;
        }
        return null;
    }

    /**
     * Generates a response based on the input message.
     * @param {string} message - The input message.
     * @param {Object} options
     * @param {string} [options.conversation_id] - Existing conversation ID.
     * @param {string} [options.system_prompt_name] - System prompt name.
     * @param {string} [options.model_id] - Model ID.
     * @returns {Promise<string>} - The generated response.
     */
    async generate(message, { conversation_id = null, system_prompt_name = '', model_id = GrokModels.GROK_2_MINI } = {}) {
        const convoId = await this._ensureConversationId(conversation_id);
        const response = await this._streamResponse(convoId, message, system_prompt_name, model_id);
        return response.join('');
    }

    /**
     * Streams the response based on the input message.
     * @param {string} message - The input message.
     * @param {Object} options
     * @param {string} [options.conversation_id] - Existing conversation ID.
     * @param {string} [options.system_prompt_name] - System prompt name.
     * @param {string} [options.model_id] - Model ID.
     * @returns {EventEmitter} - An event emitter that emits 'data' and 'error' events.
     */
    async stream(message, { conversation_id = null, system_prompt_name = '', model_id = GrokModels.GROK_2_MINI } = {}) {
        const emitter = new EventEmitter();
        try {
            const convoId = await this._ensureConversationId(conversation_id);
            this._streamResponse(convoId, message, system_prompt_name, model_id, emitter);
        } catch (error) {
            emitter.emit('error', error);
        }
        return emitter;
    }

    /**
     * Generates an image based on the prompt.
     * @param {string} prompt - The image prompt.
     * @returns {Promise<Buffer>} - The image data.
     */
    async image(prompt) {
        const imageUrl = await this.image_url(prompt);
        const imageResponse = await fetch(imageUrl);
        if (imageResponse.ok) {
            return await imageResponse.arrayBuffer().then(buffer => Buffer.from(buffer));
        }
        throw new Error('Failed to download the image');
    }

    /**
     * Retrieves the image URL based on the prompt.
     * @param {string} prompt - The image prompt.
     * @returns {Promise<string>} - The image URL.
     */
    async image_url(prompt) {
        const conversation_id = await this.createConversation();
        if (!conversation_id) {
            throw new Error('Failed to create conversation');
        }
        const imagePrompt = `Generate an image of "${prompt}"`;
        const response = await this._streamResponse(conversation_id, imagePrompt, '', GrokModels.GROK_2_MINI);
        for (const chunk of response) {
            try {
                const data = JSON.parse(chunk);
                if (data.result && data.result.imageAttachment && data.result.imageAttachment.imageUrl) {
                    return data.result.imageAttachment.imageUrl;
                }
            } catch (e) {
                continue;
            }
        }
        throw new Error('Failed to generate the image');
    }

    async _ensureConversationId(conversation_id) {
        if (!conversation_id) {
            conversation_id = await this.createConversation();
            if (!conversation_id) {
                throw new Error('Failed to create conversation');
            }
        }
        return conversation_id;
    }

    async _streamResponse(conversation_id, message, system_prompt_name, model_id, emitter = null) {
        const url = 'https://api.x.com/2/grok/add_response.json';
        const payload = this._createAddResponsePayload(conversation_id, message, system_prompt_name, model_id);

        try {
            const response = await fetch(url, {
                method: 'POST',
                headers: this.headers,
                body: JSON.stringify(payload),
            });

            if (!response.ok) {
                const errorText = await response.text();
                if (emitter) {
                    emitter.emit('error', new Error(`Error adding response: ${errorText}`));
                } else {
                    console.error(`Error adding response: ${errorText}`);
                }
                return [];
            }

            const reader = response.body.getReader();
            const decoder = new TextDecoder('utf-8');
            let doneReading = false;
            const result = [];

            while (!doneReading) {
                const { value, done } = await reader.read();
                if (done) {
                    doneReading = true;
                    break;
                }
                const chunk = decoder.decode(value, { stream: true });
                const lines = chunk.split('\n').filter(line => line.trim() !== '');
                for (const line of lines) {
                    try {
                        const parsed = JSON.parse(line);
                        if (parsed.result) {
                            if (parsed.result.message) {
                                result.push(parsed.result.message);
                                if (emitter) emitter.emit('data', parsed.result.message);
                            } else if (parsed.result.imageAttachment) {
                                const jsonString = JSON.stringify(parsed);
                                result.push(jsonString);
                                if (emitter) emitter.emit('data', jsonString);
                            }
                        }
                    } catch (e) {

                        continue;
                    }
                }
            }

            return result;
        } catch (error) {
            if (emitter) {
                emitter.emit('error', error);
            } else {
                console.error(`Error adding response: ${error.message}`);
            }
            return [];
        }
    }

    async _makeRequest(url, payload) {
        try {
            const response = await fetch(url, {
                method: 'POST',
                headers: this.headers,
                body: JSON.stringify(payload),
            });
            if (response.ok) {
                return await response.json();
            } else {
                const errorText = await response.text();
                console.error(`Error making request: ${errorText}`);
                return null;
            }
        } catch (error) {
            console.error(`Request failed: ${error.message}`);
            return null;
        }
    }

    _createAddResponsePayload(conversation_id, message, system_prompt_name, model_id) {
        return {
            responses: [
                {
                    message: message,
                    sender: 1,
                },
            ],
            systemPromptName: system_prompt_name,
            grokModelOptionId: typeof model_id === 'object' ? model_id.value : model_id,
            conversationId: conversation_id,
        };
    }
}

module.exports = { Grokit, GrokModels };
// app.js
const { Grokit, GrokModels } = require('./grokit');

// Extract tokens from cookies
const auth_token = "***";
const csrf_token = "***";

(async () => {
    try {
        // Initialize Grokit instance
        const grok = new Grokit({
            auth_token: auth_token,
            csrf_token: csrf_token,
        });

        // Test with a sample question
        const response = await grok.generate('Who are you?, { model_id: GrokModels.GROK_2_MINI });
        console.log('Generated Response:', response);
    } catch (error) {
        console.error('Error:', error);
    }
})();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions