| FROM node:20-slim |
|
|
| WORKDIR /app |
|
|
| RUN cat <<'EOF' > /app/package.json |
| { |
| "name": "gemini-api-server", |
| "version": "1.0.0", |
| "main": "index.js", |
| "scripts": { |
| "start": "node index.js" |
| }, |
| "dependencies": { |
| "axios": "^1.6.8", |
| "cors": "^2.8.5", |
| "express": "^4.19.2" |
| } |
| } |
| EOF |
|
|
| RUN npm install --only=production |
|
|
| RUN cat <<'EOF' > /app/index.js |
| const express = require('express'); |
| const cors = require('cors'); |
| const axios = require('axios'); |
| const crypto = require('crypto'); |
|
|
| const app = express(); |
| const PORT = 7860; |
| const VALIDATED_TOKEN = 'a38f5889-8fef-46d4-8ede-bf4668b6a9bb'; |
|
|
| const firstNames = ['John', 'Jane', 'Alex', 'Emily', 'Chris', 'Katie', 'Michael', 'Sarah', 'David', 'Laura', 'James', 'Linda']; |
| const lastNames = ['Smith', 'Doe', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez', 'Wilson']; |
|
|
| const generateRandomUser = () => { |
| const firstName = firstNames[Math.floor(Math.random() * firstNames.length)]; |
| const lastName = lastNames[Math.floor(Math.random() * lastNames.length)]; |
| const fullName = `${firstName} ${lastName}`; |
| const emailUsername = `${firstName.toLowerCase()}.${lastName.toLowerCase()}${Math.floor(Math.random() * 999)}`; |
| const email = `${emailUsername}@gmail.com`; |
| const id = Array.from({ length: 21 }, () => Math.floor(Math.random() * 10)).join(''); |
| const image = `https://robohash.org/${id}.png?set=set2&bgset=bg1&size=96x96`; |
|
|
| return { name: fullName, email, image, id }; |
| }; |
|
|
| const generateId = (size = 7) => { |
| const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
| const randomBytes = crypto.randomBytes(size); |
| return Array.from({ length: size }, (_, i) => alphabet[randomBytes[i] % alphabet.length]).join(''); |
| }; |
|
|
| const parseApiResponse = (data) => { |
| const delimiter = '$~~~$'; |
| if (typeof data === 'string' && data.includes(delimiter)) { |
| const parts = data.split(delimiter); |
| try { |
| const sources = JSON.parse(parts[1]); |
| const answer = parts[2] ? parts[2].trim() : ''; |
| return { answer, sources }; |
| } catch { |
| return { answer: data, sources: [] }; |
| } |
| } |
| return { answer: data, sources: [] }; |
| }; |
|
|
| app.use(cors()); |
| app.use(express.json()); |
|
|
| app.post('/api/generate', async (req, res) => { |
| const { prompt, system, web } = req.body; |
|
|
| if (!prompt) { |
| return res.status(400).json({ error: 'Request body harus menyertakan "prompt"' }); |
| } |
|
|
| try { |
| const newUserMessage = { role: 'user', content: prompt, id: generateId() }; |
| const messagesForPayload = [newUserMessage]; |
|
|
| let webSearchModeOption = { autoMode: true, webMode: false, offlineMode: false }; |
| if (web) { |
| const webMode = String(web).toLowerCase(); |
| if (webMode === 'true') webSearchModeOption = { autoMode: false, webMode: true, offlineMode: false }; |
| else if (webMode === 'false') webSearchModeOption = { autoMode: false, webMode: false, offlineMode: true }; |
| } |
|
|
| const randomUser = generateRandomUser(); |
| const expiresDate = new Date(); |
| expiresDate.setFullYear(expiresDate.getFullYear() + 1); |
|
|
| const payload = { |
| messages: messagesForPayload, |
| id: newUserMessage.id, |
| userSystemPrompt: system || null, |
| validated: VALIDATED_TOKEN, |
| previewToken: null, |
| userId: null, |
| codeModelMode: true, |
| trendingAgentMode: {}, |
| isMicMode: false, |
| maxTokens: 1024, |
| playgroundTopP: null, |
| playgroundTemperature: null, |
| isChromeExt: false, |
| githubToken: '', |
| clickedAnswer2: false, |
| clickedAnswer3: false, |
| clickedForceWebSearch: false, |
| visitFromDelta: false, |
| isMemoryEnabled: false, |
| mobileClient: false, |
| userSelectedModel: null, |
| userSelectedAgent: 'VscodeAgent', |
| imageGenerationMode: false, |
| imageGenMode: 'autoMode', |
| webSearchModePrompt: false, |
| deepSearchMode: false, |
| domains: null, |
| vscodeClient: false, |
| codeInterpreterMode: false, |
| customProfile: { |
| name: '', |
| occupation: '', |
| traits: [], |
| additionalInfo: '', |
| enableNewChats: false, |
| }, |
| webSearchModeOption, |
| session: { |
| user: randomUser, |
| expires: expiresDate.toISOString(), |
| isNewUser: Math.random() < 0.1, |
| }, |
| isPremium: false, |
| subscriptionCache: { |
| status: 'FREE', |
| expiryTimestamp: null, |
| lastChecked: Date.now(), |
| isTrialSubscription: false, |
| }, |
| beastMode: false, |
| reasoningMode: false, |
| designerMode: false, |
| workspaceId: '', |
| asyncMode: false, |
| integrations: {}, |
| isTaskPersistent: false, |
| selectedElement: null, |
| }; |
|
|
| const chatApiUrl = 'https://www.blackbox.ai/api/chat'; |
| const headers = { |
| Accept: '*/*', |
| 'Content-Type': 'application/json', |
| Origin: 'https://www.blackbox.ai', |
| Referer: 'https://www.blackbox.ai/', |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', |
| }; |
|
|
| const chatResponse = await axios.post(chatApiUrl, payload, { headers }); |
| const assistantRawResponse = chatResponse.data; |
| const parsedResult = parseApiResponse(assistantRawResponse); |
|
|
| res.send(parsedResult.answer); |
|
|
| } catch (error) { |
| console.error("Error saat scraping Blackbox AI:", error); |
| res.status(500).send("Terjadi kesalahan pada server saat memproses permintaan Anda."); |
| } |
| }); |
|
|
| app.listen(PORT, () => { |
| console.log(`Server berjalan di http://localhost:${PORT}`); |
| }); |
| EOF |
|
|
| EXPOSE 7860 |
|
|
| CMD ["npm", "start"] |