Juanoto2012 commited on
Commit
870c749
·
verified ·
1 Parent(s): b351d1f

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +207 -1
server.js CHANGED
@@ -141,4 +141,210 @@ app.get('/v1/models', async (req, res) => {
141
  try {
142
  const allModels = await fetchAllModels();
143
  const textModels = allModels
144
- .filter(m => !isImageModel(m)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  try {
142
  const allModels = await fetchAllModels();
143
  const textModels = allModels
144
+ .filter(m => !isImageModel(m) && m.supports_chat !== false)
145
+ .map(m => { m.type = 'text'; return m; });
146
+ res.json({ object: "list", data: textModels });
147
+ } catch (error) {
148
+ res.status(500).json({ error: "No models available." });
149
+ }
150
+ });
151
+
152
+ app.get('/v1/images/models', async (req, res) => {
153
+ try {
154
+ const allModels = await fetchAllModels();
155
+ let imageModels = allModels
156
+ .filter(m => isImageModel(m))
157
+ .map(m => { m.type = 'image'; return m; });
158
+
159
+ const baseImages = [
160
+ { id: "flux", object: "model", type: "image", owned_by: "system" },
161
+ { id: "dall-e-3", object: "model", type: "image", owned_by: "system" }
162
+ ];
163
+
164
+ baseImages.forEach(baseMod => {
165
+ if (!imageModels.find(m => m.id.toLowerCase() === baseMod.id)) imageModels.push(baseMod);
166
+ });
167
+
168
+ res.json({ object: "list", data: imageModels });
169
+ } catch (error) {
170
+ res.status(500).json({ error: "No models available." });
171
+ }
172
+ });
173
+
174
+ app.post(['/v1/chat/completions', '/v1/images/generations'], limiter, async (req, res) => {
175
+ const isImage = req.path === '/v1/images/generations';
176
+ let availableProviders = isImage ? PROVIDERS.filter(p => p.imageUrl) : [...PROVIDERS];
177
+ if (isImage && availableProviders.length === 0) availableProviders = [...PROVIDERS];
178
+
179
+ const startTime = Date.now();
180
+ let responseSent = false;
181
+
182
+ // Extraemos la IP del cliente para reenviarla
183
+ const clientIp = req.ip || req.headers['x-forwarded-for'] || req.socket.remoteAddress;
184
+
185
+ let payload = JSON.stringify(req.body);
186
+ req.body = null;
187
+
188
+ while (availableProviders.length > 0 && Date.now() - startTime < QUEUE_TIMEOUT) {
189
+ let selectedProvider = null;
190
+ let shuffled = [...availableProviders].sort(() => Math.random() - 0.5);
191
+
192
+ for (let provider of shuffled) {
193
+ if (currentLoad[provider.id] < MAX_PER_PROVIDER) {
194
+ selectedProvider = provider;
195
+ currentLoad[provider.id]++;
196
+ break;
197
+ }
198
+ }
199
+
200
+ if (!selectedProvider) {
201
+ await new Promise(r => setTimeout(r, 1500));
202
+ continue;
203
+ }
204
+
205
+ let isReleased = false;
206
+ const releaseSlot = () => {
207
+ if (!isReleased) {
208
+ currentLoad[selectedProvider.id] = Math.max(0, currentLoad[selectedProvider.id] - 1);
209
+ isReleased = true;
210
+ }
211
+ };
212
+
213
+ try {
214
+ let targetUrl = isImage && selectedProvider.imageUrl ? selectedProvider.imageUrl : selectedProvider.url;
215
+
216
+ // --- OFUSCACIÓN + DELEGACIÓN DE IP ---
217
+ const fetchHeaders = {
218
+ "Content-Type": "application/json",
219
+ "User-Agent": getRandomUserAgent(),
220
+ "Accept": "*/*",
221
+ "Connection": "keep-alive",
222
+ "X-Forwarded-For": clientIp, // El proveedor rate-limitea esta IP
223
+ "X-Real-IP": clientIp // El proveedor rate-limitea esta IP
224
+ };
225
+
226
+ // 🔥 INYECCIÓN DE DUMMY KEY PARA VOIDS-API 🔥
227
+ if (selectedProvider.id === "voids-api") {
228
+ fetchHeaders["Authorization"] = "Bearer sk-dummy-voids-key-12345";
229
+ }
230
+
231
+ const response = await fetch(targetUrl, {
232
+ method: "POST",
233
+ headers: fetchHeaders,
234
+ body: payload
235
+ });
236
+
237
+ if (!response.ok) {
238
+ releaseSlot();
239
+ availableProviders = availableProviders.filter(p => p.id !== selectedProvider.id);
240
+ continue;
241
+ }
242
+
243
+ const responseHeaders = new Headers(response.headers);
244
+ responseHeaders.delete('set-cookie');
245
+ responseHeaders.delete('server');
246
+ responseHeaders.delete('x-powered-by');
247
+ responseHeaders.delete('cf-ray');
248
+ responseHeaders.delete('access-control-allow-origin');
249
+
250
+ if (isImage) {
251
+ const contentType = responseHeaders.get("content-type") || "";
252
+
253
+ if (contentType.includes("application/json")) {
254
+ const jsonResp = await response.json();
255
+ let dataArray = jsonResp.data;
256
+ if (!dataArray && jsonResp.url) dataArray = [{ url: jsonResp.url }];
257
+
258
+ if (dataArray && Array.isArray(dataArray)) {
259
+ for (let item of dataArray) {
260
+ if (item.url && !item.b64_json) {
261
+ try {
262
+ const imgRes = await fetch(item.url);
263
+ const arrayBuffer = await imgRes.arrayBuffer();
264
+ item.b64_json = Buffer.from(arrayBuffer).toString('base64');
265
+ delete item.url;
266
+ } catch (e) {}
267
+ }
268
+ }
269
+ releaseSlot();
270
+ responseSent = true;
271
+ payload = null;
272
+
273
+ return res.status(response.status).json({
274
+ created: Math.floor(Date.now() / 1000),
275
+ data: dataArray
276
+ });
277
+ }
278
+
279
+ releaseSlot();
280
+ responseSent = true;
281
+ payload = null;
282
+ return res.status(response.status).json(jsonResp);
283
+ }
284
+ else if (contentType.includes("image/")) {
285
+ const arrayBuffer = await response.arrayBuffer();
286
+ const b64 = Buffer.from(arrayBuffer).toString('base64');
287
+ releaseSlot();
288
+ responseSent = true;
289
+ payload = null;
290
+ return res.status(200).json({
291
+ created: Math.floor(Date.now() / 1000),
292
+ data: [{ b64_json: b64 }]
293
+ });
294
+ }
295
+ else {
296
+ const textResp = await response.text();
297
+ releaseSlot();
298
+ responseSent = true;
299
+ payload = null;
300
+ return res.status(response.status).type(contentType).send(textResp);
301
+ }
302
+ }
303
+
304
+ res.writeHead(response.status, {
305
+ 'Content-Type': responseHeaders.get('content-type') || 'text/event-stream',
306
+ 'Cache-Control': 'no-cache',
307
+ 'Connection': 'keep-alive'
308
+ });
309
+
310
+ if (response.body) {
311
+ const stream = Readable.fromWeb(response.body);
312
+ stream.pipe(res);
313
+
314
+ stream.on('end', () => {
315
+ releaseSlot();
316
+ payload = null;
317
+ });
318
+ stream.on('error', () => {
319
+ releaseSlot();
320
+ payload = null;
321
+ });
322
+ req.on('close', () => {
323
+ releaseSlot();
324
+ payload = null;
325
+ });
326
+ } else {
327
+ releaseSlot();
328
+ payload = null;
329
+ res.end();
330
+ }
331
+
332
+ responseSent = true;
333
+ return;
334
+
335
+ } catch (err) {
336
+ releaseSlot();
337
+ availableProviders = availableProviders.filter(p => p.id !== selectedProvider.id);
338
+ }
339
+ }
340
+
341
+ payload = null;
342
+
343
+ if (!responseSent) {
344
+ return res.status(503).json({ error: { message: "Servicio no disponible.", code: 503 } });
345
+ }
346
+ });
347
+
348
+ app.listen(PORT, '0.0.0.0', () => {
349
+ console.log(`[SYS] Nivel de cifrado: Tor (Delegando IP). Concurrencia máxima: 500/prov. Puerto: ${PORT}`);
350
+ });