gemmy.mjs

javascriptCreated 20 Jan 2026, 08:3095 views
AI Chat & Image Generator Wrapper Gemmy apk.
#ai#chatbot#smart
javascript
/***
  @ Base: https://play.google.com/store/apps/details?id=com.jetkite.gemmy
  @ Author: Shannz
  @ Note: AI Chat & Image Generator Wrapper Gemmy apk.
***/

import axios from 'axios';
import fs from 'fs';
import crypto from 'crypto';
import { fileTypeFromBuffer } from 'file-type';

const CONFIG = {
    GEMINI: {
        URL: "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent",
        API_KEY: "AIzaSyAKbxdxfyNoQMx9ft9xAVoQWrwpN9JnphY",
        HEADERS: {
            'User-Agent': 'okhttp/5.3.2',
            'Accept-Encoding': 'gzip',
            'x-goog-api-key': 'AIzaSyAKbxdxfyNoQMx9ft9xAVoQWrwpN9JnphY',
            'x-android-package': 'com.jetkite.gemmy',
            'x-android-cert': '037CD2976D308B4EFD63EC63C48DC6E7AB7E5AF2',
            'content-type': 'application/json; charset=UTF-8'
        }
    },
    IMAGEN: {
        URL: "https://firebasevertexai.googleapis.com/v1beta/projects/gemmy-ai-bdc03/models/imagen-4.0-fast-generate-001:predict",
        HEADERS: {
            'User-Agent': 'ktor-client',
            'Accept': 'application/json',
            'Accept-Encoding': 'gzip',
            'Content-Type': 'application/json',
            'x-goog-api-key': 'AIzaSyAxof8_SbpDcww38NEQRhNh0Pzvbphh-IQ',
            'x-goog-api-client': 'gl-kotlin/2.2.21-ai fire/17.7.0',
            'x-firebase-appid': '1:652803432695:android:c4341db6033e62814f33f2',
            'x-firebase-appversion': '91',
            'x-firebase-appcheck': 'eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ==',
            'accept-charset': 'UTF-8'
        }
    }
};

// bisa di costume prompt kalo mau
const SYSTEM_INSTRUCTION = {
    role: "user",
    parts: [{
        text: "You are a helpful assistant. Keep your answers concise. Provide no more than 3–4 paragraphs unless the user explicitly asks for a longer explanation."
    }]
};

const uploadToCloud = async (buffer) => {
    try {
        const filename = `gemmy-${crypto.randomUUID()}.png`;
        const { data } = await axios.post('https://api.cloudsky.biz.id/get-upload-url', {
            fileKey: filename,
            contentType: 'image/png',
            fileSize: buffer.length
        });

        await axios.put(data.uploadUrl, buffer, {
            headers: { 
                'Content-Type': 'image/png', 
                'Content-Length': buffer.length,
                'x-amz-server-side-encryption': 'AES256' 
            }
        });

        return `https://api.cloudsky.biz.id/file?key=${encodeURIComponent(filename)}`;
    } catch (error) {
        console.error(`[Cloud Upload Error]: ${error.message}`);
        return null;
    }
};

const toBase64 = async (input) => {
    try {
        let buffer;
        if (Buffer.isBuffer(input)) {
            buffer = input;
        } else if (input.startsWith('http')) {
            const res = await axios.get(input, { responseType: 'arraybuffer' });
            buffer = Buffer.from(res.data);
        } else if (fs.existsSync(input)) {
            buffer = fs.readFileSync(input);
        } else {
            return null;
        }
        return buffer.toString('base64');
    } catch (e) { return null; }
};

const getMimeType = (pathOrUrl) => {
    const ext = pathOrUrl.split('.').pop().toLowerCase();
    const mimes = { 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'png': 'image/png', 'webp': 'image/webp' };
    return mimes[ext] || 'application/octet-stream';
};

export const gemmy = {
    chat: async (prompt, history = [], media = null) => {
        try {
            let parts = [];

            if (media) {
                const base64Data = await toBase64(media);
                if (base64Data) {
                    const isImage = typeof media === 'string' && /\.(jpg|jpeg|png|webp)$/i.test(media);
                    
                    if (isImage) {
                        parts.push({
                            inlineData: {
                                mimeType: getMimeType(media),
                                data: base64Data
                            }
                        });
                        parts.push({ text: prompt });
                    } else {
                        const decodedText = Buffer.from(base64Data, 'base64').toString('utf-8');
                        parts.push({ 
                            text: `${prompt}\n\n--- DOCUMENT CONTENT ---\n\n${decodedText}` 
                        });
                    }
                } else {
                    parts.push({ text: prompt });
                }
            } else {
                parts.push({ text: prompt });
            }

            const newHistory = [
                ...history,
                {
                    role: "user",
                    parts: parts
                }
            ];

            const payload = {
                contents: newHistory,
                generationConfig: {
                    maxOutputTokens: 800,
                    temperature: 0.9
                },
                systemInstruction: SYSTEM_INSTRUCTION
            };

            const response = await axios.post(CONFIG.GEMINI.URL, payload, {
                headers: CONFIG.GEMINI.HEADERS
            });

            const result = response.data;
            
            if (result.candidates && result.candidates.length > 0) {
                const reply = result.candidates[0].content;
                newHistory.push(reply);
                
                return {
                    success: true,
                    reply: reply.parts[0].text,
                    history: newHistory,
                    usage: result.usageMetadata
                };
            }

            return { success: false, msg: 'No response candidates found' };

        } catch (error) {
            console.error(`[Gemini Chat Error]: ${error.message}`);
            return { success: false, msg: error.message };
        }
    },

    generateImage: async (prompt, options = {}) => {
        try {
            const payload = {
                instances: [
                    { prompt: prompt }
                ],
                parameters: {
                    sampleCount: 1,
                    includeRaiReason: true,
                    includeSafetyAttributes: true,
                    aspectRatio: options.aspectRatio || "1:1",
                    safetySetting: "block_low_and_above",
                    personGeneration: "allow_adult",
                    imageOutputOptions: {
                        mimeType: "image/jpeg",
                        compressionQuality: 100
                    }
                }
            };

            const response = await axios.post(CONFIG.IMAGEN.URL, payload, {
                headers: CONFIG.IMAGEN.HEADERS
            });

            const predictions = response.data.predictions;
            if (predictions && predictions.length > 0 && predictions[0].bytesBase64Encoded) {
                const imgBuffer = Buffer.from(predictions[0].bytesBase64Encoded, 'base64');
                const url = await uploadToCloud(imgBuffer);
                
                if (url) {
                    return {
                        success: true,
                        url: url,
                        safetyAttributes: predictions[0].safetyAttributes
                    };
                } else {
                    return { success: false, msg: 'Failed to upload image to cloud' };
                }
            }

            return { success: false, msg: 'No image generated' };

        } catch (error) {
            console.error(`[Imagen Error]: ${error.message}`);
            return { success: false, msg: error.message };
        }
    }
};

/*
(async () => {
    // 1. Contoh Chat Biasa
    console.log("--- Tes Chat ---");
    let chatRes = await gemmy.chat("Siapa itu Jokowi?");
    console.log("Bot:", chatRes.reply);
    
    // Simpan history untuk konteks selanjutnya
    let myHistory = chatRes.history;

    // 2. Contoh Chat dengan Gambar
    console.log("\n--- Tes Vision ---");
    let visionRes = await gemmy.chat(
        "Gambar apa ini? dan apakah ada hubungannya dengan pertanyaan saya sebelumnya?", 
        myHistory, //history sebelumnya
        "./u.jpg" //bisa path bisa url
    ); 
    console.log("Bot Vision:", visionRes.reply);
    
    // 3. Contoh Chat dengan file
    console.log("\n--- Tes Dengan File ---");
    let fileRes = await gemmy.chat(
        "Tolong jelaskan apa fungsi file ini dan dependency apa saja yang dipakai?", 
        [], // tanpa history 
        "./s.py" // file nya wajib path
    );
    console.log("Bot File:", fileRes.reply);

    // 4. Contoh Generate Image (Imagen)
    console.log("\n--- Tes Generate Image ---");
    let imgRes = await gemmy.generateImage(
        "cyberpunk cat neon lights", 
        { aspectRatio: "16:9" } //opsional bisa di sesuaikan ukurannya 
    );
    console.log("Image URL:", imgRes.url);
})();
*/