Update Dockerfile
Browse files- Dockerfile +78 -135
Dockerfile
CHANGED
|
@@ -5,7 +5,7 @@ WORKDIR /app
|
|
| 5 |
RUN cat <<'EOF' > /app/package.json
|
| 6 |
{
|
| 7 |
"name": "gemini-api-server",
|
| 8 |
-
"version": "1.0.0
|
| 9 |
"main": "index.js",
|
| 10 |
"scripts": {
|
| 11 |
"start": "node index.js"
|
|
@@ -24,30 +24,32 @@ RUN cat <<'EOF' > /app/index.js
|
|
| 24 |
const express = require('express');
|
| 25 |
const cors = require('cors');
|
| 26 |
const axios = require('axios');
|
| 27 |
-
const crypto = require('crypto');
|
| 28 |
|
| 29 |
const app = express();
|
| 30 |
const PORT = 7860;
|
| 31 |
-
const VALIDATED_TOKEN = 'a38f5889-8fef-46d4-8ede-bf4668b6a9bb';
|
| 32 |
|
| 33 |
-
const
|
| 34 |
-
const lastNames = ['Smith', 'Doe', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez', 'Wilson'];
|
| 35 |
|
| 36 |
-
const
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
};
|
| 46 |
|
| 47 |
const generateId = (size = 7) => {
|
| 48 |
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| 49 |
-
|
| 50 |
-
return Array.from({ length: size }, (_, i) => alphabet[randomBytes[i] % alphabet.length]).join('');
|
| 51 |
};
|
| 52 |
|
| 53 |
const parseApiResponse = (data) => {
|
|
@@ -55,146 +57,87 @@ const parseApiResponse = (data) => {
|
|
| 55 |
if (typeof data === 'string' && data.includes(delimiter)) {
|
| 56 |
const parts = data.split(delimiter);
|
| 57 |
try {
|
| 58 |
-
const sources = JSON.parse(parts[1]);
|
| 59 |
const answer = parts[2] ? parts[2].trim() : '';
|
| 60 |
-
return
|
| 61 |
-
} catch {
|
| 62 |
-
return { answer: data, sources: [] };
|
| 63 |
-
}
|
| 64 |
}
|
| 65 |
-
return
|
| 66 |
};
|
| 67 |
|
| 68 |
-
const createPayload = (prompt
|
| 69 |
-
const newUserMessage = { role: 'user', content: prompt, id: generateId() };
|
| 70 |
-
const messagesForPayload = [newUserMessage];
|
| 71 |
-
|
| 72 |
-
let webSearchModeOption = { autoMode: true, webMode: false, offlineMode: false };
|
| 73 |
-
if (web) {
|
| 74 |
-
const webMode = String(web).toLowerCase();
|
| 75 |
-
if (webMode === 'true') webSearchModeOption = { autoMode: false, webMode: true, offlineMode: false };
|
| 76 |
-
else if (webMode === 'false') webSearchModeOption = { autoMode: false, webMode: false, offlineMode: true };
|
| 77 |
-
}
|
| 78 |
-
|
| 79 |
-
const randomUser = generateRandomUser();
|
| 80 |
-
const expiresDate = new Date();
|
| 81 |
-
expiresDate.setFullYear(expiresDate.getFullYear() + 1);
|
| 82 |
-
|
| 83 |
return {
|
| 84 |
-
messages:
|
| 85 |
-
id:
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
imageGenerationMode: false,
|
| 107 |
-
imageGenMode:
|
| 108 |
-
webSearchModePrompt: false,
|
| 109 |
-
deepSearchMode: false,
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
|
|
|
| 119 |
},
|
| 120 |
-
isPremium: false,
|
| 121 |
-
subscriptionCache: { status:
|
| 122 |
-
beastMode: false,
|
| 123 |
-
reasoningMode: false,
|
| 124 |
-
designerMode: false,
|
| 125 |
-
workspaceId:
|
| 126 |
-
asyncMode: false,
|
| 127 |
-
integrations: {},
|
| 128 |
-
isTaskPersistent: false,
|
| 129 |
-
selectedElement: null
|
| 130 |
};
|
| 131 |
};
|
| 132 |
|
| 133 |
app.use(cors());
|
| 134 |
app.use(express.json());
|
| 135 |
|
| 136 |
-
const chatApiUrl = 'https://www.blackbox.ai/api/chat';
|
| 137 |
-
const headers = {
|
| 138 |
-
'Accept': '*/*',
|
| 139 |
-
'Content-Type': 'application/json',
|
| 140 |
-
'Origin': 'https://www.blackbox.ai',
|
| 141 |
-
'Referer': 'https://www.blackbox.ai/',
|
| 142 |
-
'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',
|
| 143 |
-
};
|
| 144 |
-
|
| 145 |
app.post('/api/generate', async (req, res) => {
|
| 146 |
-
const { prompt
|
| 147 |
-
if (!prompt)
|
| 148 |
-
|
| 149 |
-
try {
|
| 150 |
-
const payload = createPayload(prompt, system, web);
|
| 151 |
-
const chatResponse = await axios.post(chatApiUrl, payload, { headers });
|
| 152 |
-
const parsedResult = parseApiResponse(chatResponse.data);
|
| 153 |
-
res.send(parsedResult.answer);
|
| 154 |
-
} catch (error) {
|
| 155 |
-
console.error("Error pada /api/generate:", error.message);
|
| 156 |
-
res.status(500).send("Terjadi kesalahan pada server.");
|
| 157 |
-
}
|
| 158 |
-
});
|
| 159 |
-
|
| 160 |
-
const streamResponseByWord = async (res, text, delay = 50) => {
|
| 161 |
-
const words = text.split(' ');
|
| 162 |
-
for (const word of words) {
|
| 163 |
-
res.write(word + ' ');
|
| 164 |
-
await new Promise(resolve => setTimeout(resolve, delay));
|
| 165 |
}
|
| 166 |
-
res.end();
|
| 167 |
-
};
|
| 168 |
-
|
| 169 |
-
app.post('/api/stream', async (req, res) => {
|
| 170 |
-
const { prompt, system, web } = req.body;
|
| 171 |
-
if (!prompt) return res.status(400).json({ error: 'Request body harus menyertakan "prompt"' });
|
| 172 |
-
|
| 173 |
try {
|
| 174 |
-
const payload = createPayload(prompt
|
| 175 |
-
const
|
| 176 |
-
const
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
| 180 |
-
res.setHeader('Cache-Control', 'no-cache');
|
| 181 |
-
res.setHeader('Connection', 'keep-alive');
|
| 182 |
-
|
| 183 |
-
await streamResponseByWord(res, fullAnswer);
|
| 184 |
-
|
| 185 |
} catch (error) {
|
| 186 |
-
console.error("Error pada /api/
|
| 187 |
-
|
| 188 |
-
res.status(500).send("Terjadi kesalahan pada server saat memproses permintaan.");
|
| 189 |
-
}
|
| 190 |
}
|
| 191 |
});
|
| 192 |
|
| 193 |
app.listen(PORT, () => {
|
| 194 |
console.log(`Server berjalan di http://localhost:${PORT}`);
|
| 195 |
-
console.log('
|
| 196 |
-
console.log(' - POST /api/generate (non-streaming)');
|
| 197 |
-
console.log(' - POST /api/stream (simulated streaming)');
|
| 198 |
});
|
| 199 |
EOF
|
| 200 |
|
|
|
|
| 5 |
RUN cat <<'EOF' > /app/package.json
|
| 6 |
{
|
| 7 |
"name": "gemini-api-server",
|
| 8 |
+
"version": "1.0.0,
|
| 9 |
"main": "index.js",
|
| 10 |
"scripts": {
|
| 11 |
"start": "node index.js"
|
|
|
|
| 24 |
const express = require('express');
|
| 25 |
const cors = require('cors');
|
| 26 |
const axios = require('axios');
|
|
|
|
| 27 |
|
| 28 |
const app = express();
|
| 29 |
const PORT = 7860;
|
|
|
|
| 30 |
|
| 31 |
+
const chatApiUrl = 'https://www.blackbox.ai/api/chat';
|
|
|
|
| 32 |
|
| 33 |
+
const hardcodedHeaders = {
|
| 34 |
+
'Accept': '*/*',
|
| 35 |
+
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
|
| 36 |
+
'Content-Type': 'application/json',
|
| 37 |
+
'Origin': 'https://www.blackbox.ai',
|
| 38 |
+
'Referer': 'https://www.blackbox.ai/',
|
| 39 |
+
'Sec-Ch-Ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Android WebView";v="140"',
|
| 40 |
+
'Sec-Ch-Ua-Mobile': '?1',
|
| 41 |
+
'Sec-Ch-Ua-Platform': '"Android"',
|
| 42 |
+
'Sec-Fetch-Dest': 'empty',
|
| 43 |
+
'Sec-Fetch-Mode': 'cors',
|
| 44 |
+
'Sec-Fetch-Site': 'same-origin',
|
| 45 |
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; RMX2185 Build/QP1A.190711.020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.207 Mobile Safari/537.36',
|
| 46 |
+
'X-Requested-With': 'mark.via.gp',
|
| 47 |
+
'Cookie': '__Host-authjs.csrf-token=ed355b358172e4e050f721e04571070c4fce9bc13dc1718dfbe9bc982b06f2d0%7C083bfcf62ec727151678b4d1dd305aed9bf4599f6b79640a08b79ab8c1f4f9f1; __Secure-authjs.callback-url=https%3A%2F%2Fwww.blackbox.ai%2Fchat%2Fv3lqW9e; intercom-id-x55eda6t=31841dc1-d158-4bb8-b24f-8c748509dedd; intercom-device-id-x55eda6t=c52c671c-4b1d-432f-892c-a4038dc76013; sessionId=7671e063-8a54-4b3e-96a1-439980e8a446; userCountry=%7B%22country%22%3A%22ID%22%2C%22currency%22%3A%22IDR%22%2C%22timestamp%22%3A1758795459179%2C%22expires%22%3A1759400259179%7D; discount-dialog-shown=true; ph_phc_TXdpocbGVeZVm5VJmAsHTMrCofBQu3e0kN8HGMNGTVW_posthog=%7B%22distinct_id%22%3A%2201998066-2b0a-76ff-8d4b-20b202d399d0%22%2C%22%24sesid%22%3A%5B1759069624381%2C%22019990b7-6079-739c-8ce1-d7065e91cd46%22%2C1759069560952%5D%7D; intercom-session-x55eda6t=UVcyeTZMajd6Vm1CYUNqV1pNUitDZHFYV3lsOVcrUG9Rdk1PeWJQb1c5OTI0UDgrRUNNM0NIYmdYTGlDY1ByWGZpYmEzaXlueDdGUWQ1Y0JOWDM0OEUvSHYyaDRFdUxLQVZwWUpqM3RYRms9LS1OTVh5TVRDY0tJR3kxaFNzMExCY3lnPT0=--e7f6016070d315ac11335141bcebc9394a68d7f7; __Secure-authjs.session-token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoiUGlDZ216aEVpaHh1enpfRVQwVms0WENENDR6Z2FjRTcyOTV4T2VFWkFJblFFZTJhMUV4eWZ1akpIdDJmeG5qSzFPME9qTDFXYVliVlNjWlRXNHJoR0EifQ..iSV2pccgt2nqwH0_m1hyvQ.Ppx_FjkipBsnPN46_l1wIaHIIm8oitiJQvyMNWYLicl12sfjj6GvMrGqlestre-_5qQRAYbcAzwSxzNSAXhDGf8Wk8tleslL9DFxBpUr8yDE-cKWURAjPfR-n0_0wuz8dsuvPH9E_2_fj2I6nNbNS9CS1tG6Nteq9yHazEwlOZXbuQ34gQRGB2lcazSFPBvKHr2402htSysMcVWh8WZearczfZ0S7aIFkd_6QO4-hKkayPo7j23syZYwaIun04dU6MHSxKbuOuIvJTz7wEjW7RYwPhx2Fyh8o1iLjDQBh9eXlRD6ZTFDQURi-gxuRwzl1AhaBJ6cYkLDdOb4SzkpDRC-OXQ1GkikZYoYdTxl1vIZFELHQ_FiZAes4RfnjGNdx5pkhEQ7I82ixP9bPW9BWVeSFtGnHLWl3yuW0gXwvDDlsQjQmrUZCtAoL0_M00NEiWPeX0ePG73cAsENzKnAXZiFpDDTmtQ78nrQVh4plhXC0GmRcGGGjTmML61MBnBJUBXhQtx0h102cuYTWKO3ET5pWfVP9Kb_sZQh-CCpEr0.kiIiz5OSA-68BCVIF5MQvpV4XZRzHo1OmVwVM-qlY84; ph_phc_9T0rgpbTO2ItkwbH8HNZuavYKcQ3h3wxzJwELM6JHV4_posthog=%7B%22distinct_id%22%3A%220199463a-b34d-76e9-be02-2925eae882fa%22%2C%22%24sesid%22%3A%5B1759142073019%2C%2201999508-4136-7e06-a044-1ca9903d8020%22%2C1759141970229%5D%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fwww.blackbox.ai%2F%22%7D%7D'
|
| 48 |
};
|
| 49 |
|
| 50 |
const generateId = (size = 7) => {
|
| 51 |
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| 52 |
+
return Array.from({ length: size }, () => alphabet[Math.floor(Math.random() * alphabet.length)]).join('');
|
|
|
|
| 53 |
};
|
| 54 |
|
| 55 |
const parseApiResponse = (data) => {
|
|
|
|
| 57 |
if (typeof data === 'string' && data.includes(delimiter)) {
|
| 58 |
const parts = data.split(delimiter);
|
| 59 |
try {
|
|
|
|
| 60 |
const answer = parts[2] ? parts[2].trim() : '';
|
| 61 |
+
return answer;
|
| 62 |
+
} catch { return data; }
|
|
|
|
|
|
|
| 63 |
}
|
| 64 |
+
return data;
|
| 65 |
};
|
| 66 |
|
| 67 |
+
const createPayload = (prompt) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
return {
|
| 69 |
+
"messages": [{ "role": "user", "content": prompt, "id": generateId() }],
|
| 70 |
+
"id": generateId(),
|
| 71 |
+
"previewToken": null,
|
| 72 |
+
"userId": null,
|
| 73 |
+
"codeModelMode": true,
|
| 74 |
+
"trendingAgentMode": {},
|
| 75 |
+
"isMicMode": false,
|
| 76 |
+
"userSystemPrompt": null,
|
| 77 |
+
"maxTokens": 1024,
|
| 78 |
+
"playgroundTopP": null,
|
| 79 |
+
"playgroundTemperature": null,
|
| 80 |
+
"isChromeExt": false,
|
| 81 |
+
"githubToken": "",
|
| 82 |
+
"clickedAnswer2": false,
|
| 83 |
+
"clickedAnswer3": false,
|
| 84 |
+
"clickedForceWebSearch": false,
|
| 85 |
+
"visitFromDelta": false,
|
| 86 |
+
"isMemoryEnabled": false,
|
| 87 |
+
"mobileClient": false,
|
| 88 |
+
"userSelectedModel": null,
|
| 89 |
+
"userSelectedAgent": "VscodeAgent",
|
| 90 |
+
"validated": "a38f5889-8fef-46d4-8ede-bf4668b6a9bb",
|
| 91 |
+
"imageGenerationMode": false,
|
| 92 |
+
"imageGenMode": "autoMode",
|
| 93 |
+
"webSearchModePrompt": false,
|
| 94 |
+
"deepSearchMode": false,
|
| 95 |
+
"promptSelection": "",
|
| 96 |
+
"domains": null,
|
| 97 |
+
"vscodeClient": false,
|
| 98 |
+
"codeInterpreterMode": false,
|
| 99 |
+
"customProfile": { "name": "", "occupation": "", "traits": [], "additionalInfo": "", "enableNewChats": false },
|
| 100 |
+
"webSearchModeOption": { "autoMode": true, "webMode": false, "offlineMode": false },
|
| 101 |
+
"session": {
|
| 102 |
+
"user": { "name": "Riki PurPur", "email": "rikipurpur98@gmail.com", "image": "https://lh3.googleusercontent.com/a/ACg8ocKHaWelcSDldvbm6wh0CegljUr_Iyv8NYNFVlaCb0qk_LrecA4=s96-c", "id": "105532451547066425912" },
|
| 103 |
+
"expires": "2025-10-29T10:34:29.189Z",
|
| 104 |
+
"isNewUser": false
|
| 105 |
},
|
| 106 |
+
"isPremium": false,
|
| 107 |
+
"subscriptionCache": { "status": "FREE", "customerId": null, "expiryTimestamp": null, "lastChecked": 1759069451898, "isTrialSubscription": false, "hasPaymentVerificationFailure": false, "verificationFailureTimestamp": null, "requiresAuthentication": false },
|
| 108 |
+
"beastMode": false,
|
| 109 |
+
"reasoningMode": false,
|
| 110 |
+
"designerMode": false,
|
| 111 |
+
"workspaceId": "",
|
| 112 |
+
"asyncMode": false,
|
| 113 |
+
"integrations": {},
|
| 114 |
+
"isTaskPersistent": false,
|
| 115 |
+
"selectedElement": null
|
| 116 |
};
|
| 117 |
};
|
| 118 |
|
| 119 |
app.use(cors());
|
| 120 |
app.use(express.json());
|
| 121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
app.post('/api/generate', async (req, res) => {
|
| 123 |
+
const { prompt } = req.body;
|
| 124 |
+
if (!prompt) {
|
| 125 |
+
return res.status(400).json({ error: 'Request body harus menyertakan "prompt"' });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
try {
|
| 128 |
+
const payload = createPayload(prompt);
|
| 129 |
+
const response = await axios.post(chatApiUrl, payload, { headers: hardcodedHeaders });
|
| 130 |
+
const finalAnswer = parseApiResponse(response.data);
|
| 131 |
+
res.send(finalAnswer);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
} catch (error) {
|
| 133 |
+
console.error("Error pada /api/generate:", error.message);
|
| 134 |
+
res.status(500).send("Terjadi kesalahan pada server saat memproses permintaan.");
|
|
|
|
|
|
|
| 135 |
}
|
| 136 |
});
|
| 137 |
|
| 138 |
app.listen(PORT, () => {
|
| 139 |
console.log(`Server berjalan di http://localhost:${PORT}`);
|
| 140 |
+
console.log('Endpoint tersedia: POST /api/generate');
|
|
|
|
|
|
|
| 141 |
});
|
| 142 |
EOF
|
| 143 |
|