Dashboard Overview
+ +Use this endpoint in your applications to connect to the AI models:
+No recent conversations.
+Start chatting to see your activity here.
+diff --git "a/hf.js" "b/hf.js" new file mode 100644--- /dev/null +++ "b/hf.js" @@ -0,0 +1,3316 @@ +const express = require('express'); +const morgan = require('morgan'); +const { createProxyMiddleware } = require('http-proxy-middleware'); +const axios = require('axios'); +const url = require('url'); +const app = express(); + +// Enable logging +app.use(morgan('dev')); + +// Environment variables configuration +const PORT = process.env.HF_PORT || 7860; +const TARGET_URL = process.env.TARGET_URL || 'http://localhost:3010'; +const API_PATH = process.env.API_PATH || '/v1'; +const TIMEOUT = parseInt(process.env.TIMEOUT) || 30000; + +console.log(`Service configuration: +- Port: ${PORT} +- Target URL: ${TARGET_URL} +- API Path: ${API_PATH} +- Timeout: ${TIMEOUT}ms`); + +// Parse proxy settings +let proxyPool = []; +if (process.env.PROXY) { + proxyPool = process.env.PROXY.split(',').map(p => p.trim()).filter(p => p); + console.log(`Loaded ${proxyPool.length} proxies from environment`); + + if (proxyPool.length > 0) { + console.log('Proxy pool initialized:'); + proxyPool.forEach((proxy, index) => { + // Log with sensitive information masked + const maskedProxy = proxy.replace(/(https?:\/\/)([^:]+):([^@]+)@/, '$1$2:****@'); + console.log(` [${index + 1}] ${maskedProxy}`); + }); + } +} + +// Randomly select a proxy from the pool +function getRandomProxy() { + if (proxyPool.length === 0) return null; + const randomIndex = Math.floor(Math.random() * proxyPool.length); + const proxyUrl = proxyPool[randomIndex]; + const parsedUrl = url.parse(proxyUrl); + + return { + host: parsedUrl.hostname, + port: parsedUrl.port || 80, + auth: parsedUrl.auth ? { + username: parsedUrl.auth.split(':')[0], + password: parsedUrl.auth.split(':')[1] + } : undefined + }; +} + +// Models list API +app.get('/hf/v1/models', (req, res) => { + const models = { + "object": "list", + "data": [ + { + "id": "claude-3.5-sonnet", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gpt-4", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gpt-4o", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "claude-3-opus", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gpt-3.5-turbo", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gpt-4-turbo-2024-04-09", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gpt-4o-128k", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gemini-1.5-flash-500k", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "claude-3-haiku-200k", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "claude-3-5-sonnet-200k", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "claude-3-5-sonnet-20241022", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gpt-4o-mini", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "o1-mini", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "o1-preview", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "o1", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "claude-3.5-haiku", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gemini-exp-1206", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gemini-2.0-flash-thinking-exp", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "gemini-2.0-flash-exp", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "deepseek-v3", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + }, + { + "id": "deepseek-r1", + "object": "model", + "created": 1706745938, + "owned_by": "cursor" + } + ] + }; + res.json(models); +}); + +// Proxy forwarding using dynamic proxy pool +app.use('/hf/v1/chat/completions', (req, res, next) => { + const proxy = getRandomProxy(); + const targetEndpoint = `${TARGET_URL}${API_PATH}/chat/completions`; + + console.log(`Forwarding request to: ${targetEndpoint}`); + + const middleware = createProxyMiddleware({ + target: targetEndpoint, + changeOrigin: true, + proxy: proxy ? proxy : undefined, + timeout: TIMEOUT, + proxyTimeout: TIMEOUT, + onProxyReq: (proxyReq, req, res) => { + if (req.body) { + const bodyData = JSON.stringify(req.body); + proxyReq.setHeader('Content-Type', 'application/json'); + proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData)); + proxyReq.write(bodyData); + proxyReq.end(); + } + }, + onError: (err, req, res) => { + console.error('Proxy error:', err); + res.status(502).json({ + error: { + message: 'Proxy connection error - unable to reach target service', + type: 'proxy_error', + details: process.env.NODE_ENV === 'development' ? err.message : undefined + } + }); + }, + onProxyRes: (proxyRes, req, res) => { + console.log(`Proxy response status: ${proxyRes.statusCode}`); + + // Handle non-JSON responses + if (proxyRes.statusCode >= 400) { + let responseBody = ''; + + proxyRes.on('data', function(chunk) { + responseBody += chunk; + }); + + proxyRes.on('end', function() { + try { + // Try to parse as JSON first + JSON.parse(responseBody); + // If successful, let the normal flow continue + } catch (e) { + // If not valid JSON, override the response with a proper JSON error + const originalStatusCode = proxyRes.statusCode; + res.writeHead(originalStatusCode, {'Content-Type': 'application/json'}); + res.end(JSON.stringify({ + error: { + message: `Error from target service: ${responseBody.substring(0, 200)}${responseBody.length > 200 ? '...' : ''}`, + type: 'target_service_error', + status: originalStatusCode + } + })); + return; + } + }); + } + } + }); + + if (proxy) { + const maskedProxy = `${proxy.host}:${proxy.port}` + (proxy.auth ? ' (with auth)' : ''); + console.log(`Using proxy: ${maskedProxy}`); + } else { + console.log('Direct connection (no proxy)'); + } + + middleware(req, res, next); +}); + +// Modern enhanced dashboard homepage +app.get('/', (req, res) => { + const htmlContent = ` + + +
+ + +Use this endpoint in your applications to connect to the AI models:
+No recent conversations.
+Start chatting to see your activity here.
+