Skip to content

grokit for node.js #1

Open
Open
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions