elinai.mjs

Elin AI support follow up message and image analyze.

#ai#chatbot#smart
14
13 Jan 2026, 06:49
RawEdit
javascript0 lines
/***
  @ Base: https://play.google.com/store/apps/details?id=ai.elin.app.android
  @ Author: Shannz
  @ Note: Elin AI support follow up message and image analyze.
***/

import axios from 'axios';
import qs from 'qs';
import FormData from 'form-data';
import fs from 'fs';

const CONFIG = {
    BASE_URL: "https://api.elin.ai",
    CREDENTIALS: {
        username: '', //email lu
        password: '' //pw lu
    },
    API: {
        TOKEN: "/api/v1/auth/token",
        SESSION: "/api/v3/chats/sessions/id",
        UPLOAD: "/api/v3/content/upload",
        CHAT: (id) => `/api/v3/chats/${id}/stream`
    },
    HEADERS: {
        'User-Agent': 'Elin AI/2.8.0 (ai.elin.app.android; build:220; Android 15; Model:25028RN03A)',
        'Accept': 'application/json',
        'Accept-Encoding': 'gzip',
        'x-device-id': '540e28659b22cf05',
        'accept-language': 'en',
        'x-timezone': 'Asia/Jakarta',
        'accept-charset': 'UTF-8'
    }
};

const parseStreamResponse = (dataString) => {
    if (typeof dataString === 'object') return JSON.stringify(dataString);
    
    const lines = dataString.split('\n');
    let finalContent = "";
    for (const line of lines) {
        if (line.startsWith('data: ')) {
            try {
                const jsonStr = line.replace('data: ', '').trim();
                if (jsonStr === '[DONE]') break;
                const parsed = JSON.parse(jsonStr);
                if (parsed.content && parsed.content.type === 'markdown') {
                    finalContent = parsed.content.content;
                }
            } catch (e) {}
        }
    }
    return finalContent;
};

export const elin = {
    chat: async (prompt, options = {}) => {
        try {
            let { chatId, imagePath } = options;

            const loginData = qs.stringify(CONFIG.CREDENTIALS);
            const loginRes = await axios.post(CONFIG.BASE_URL + CONFIG.API.TOKEN, loginData, {
                headers: {
                    ...CONFIG.HEADERS,
                    'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
                }
            });
            const token = loginRes.data?.access_token;
            if (!token) throw new Error("Gagal login: Token null");

            const authHeaders = {
                ...CONFIG.HEADERS,
                'authorization': `Bearer ${token}`
            };

            if (!chatId) {
                const sessionRes = await axios.get(CONFIG.BASE_URL + CONFIG.API.SESSION, {
                    headers: authHeaders
                });
                chatId = sessionRes.data?.id;
                if (!chatId) throw new Error("Gagal create session ID baru");
            } else { }

            let messageContent;
            if (imagePath) {
                if (!fs.existsSync(imagePath)) throw new Error(`File tidak ditemukan: ${imagePath}`);
                
                const form = new FormData();
                form.append('file', fs.createReadStream(imagePath));
                
                const uploadRes = await axios.post(CONFIG.BASE_URL + CONFIG.API.UPLOAD, form, {
                    headers: { ...authHeaders, ...form.getHeaders() }
                });
                
                if (!uploadRes.data?.filename) throw new Error("Gagal upload gambar.");
                
                messageContent = {
                    type: "path",
                    content: uploadRes.data.filename,
                    context: prompt,
                    resource_type: "image"
                };
            } else {
                messageContent = {
                    type: "text",
                    content: prompt
                };
            }

            const payload = {
                id: chatId,
                messages: [{
                    type: "user",
                    order: 1,
                    timestamp: new Date().toISOString(),
                    context: {},
                    content: messageContent
                }],
                type: "generic",
                overrides: { retry: false }
            };

            const chatRes = await axios.post(CONFIG.BASE_URL + CONFIG.API.CHAT(chatId), payload, {
                headers: {
                    ...authHeaders,
                    'Content-Type': 'application/json'
                },
                responseType: 'stream'
            });

            return new Promise((resolve, reject) => {
                let fullData = '';
                chatRes.data.on('data', (chunk) => {
                    fullData += chunk.toString();
                });
                
                chatRes.data.on('end', () => {
                    const resultText = parseStreamResponse(fullData);
                    resolve({
                        status: true,
                        chatId: chatId,
                        result: resultText || "Tidak ada respon teks."
                    });
                });

                chatRes.data.on('error', (err) => reject(err));
            });

        } catch (error) {
            let errMsg = error.message;
            if (error.response) {
                 if (error.response.data && !error.response.data.read) {
                     errMsg = `Server Error (${error.response.status}): ${JSON.stringify(error.response.data)}`;
                 } else {
                     errMsg = `Server Error (${error.response.status})`;
                 }
            }
            return { status: false, error: errMsg };
        }
    }
};