deepstudio / app.py
00Boobs00's picture
Upload folder using huggingface_hub
180578f verified
/**
* DeepStudio Pro - Enhanced Production Server
* Built with anycoder β†’ https://huggingface.co/spaces/akhaliq/anycoder
*
* Features:
* - Graceful shutdown handling
* - Request logging and metrics
* - Health check endpoint
* - Memory and performance monitoring
* - Security headers
*/
const path = require('path');
const http = require('http');
const { parse } = require('url');
const dir = path.join(__dirname);
// Set production environment
process.env.NODE_ENV = 'production';
process.chdir(__dirname);
// Configuration with sensible defaults
const config = {
port: parseInt(process.env.PORT, 10) || 7860,
hostname: process.env.HOSTNAME || '0.0.0.0',
keepAliveTimeout: parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10) || 65000,
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 30000,
maxRequestsPerSocket: parseInt(process.env.MAX_REQUESTS_PER_SOCKET, 10) || 0,
};
// Next.js configuration - optimized for production
const nextConfig = {
env: {},
webpack: null,
eslint: { ignoreDuringBuilds: true },
typescript: {
ignoreBuildErrors: false,
tsconfigPath: 'tsconfig.json'
},
distDir: './.next',
cleanDistDir: true,
assetPrefix: '',
cacheMaxMemorySize: 52428800,
configOrigin: 'next.config.ts',
useFileSystemPublicRoutes: true,
generateEtags: true,
pageExtensions: ['tsx', 'ts', 'jsx', 'js'],
poweredByHeader: false, // Security: disable X-Powered-By
compress: true,
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
path: '/_next/image',
loader: 'default',
loaderFile: '',
domains: [],
disableStaticImages: false,
minimumCacheTTL: 60,
formats: ['image/webp', 'image/avif'],
dangerouslyAllowSVG: false,
contentSecurityPolicy: "script-src 'none'; frame-src 'none'; sandbox;",
contentDispositionType: 'attachment',
remotePatterns: [],
unoptimized: false,
},
devIndicators: { position: 'bottom-left' },
onDemandEntries: { maxInactiveAge: 60000, pagesBufferLength: 5 },
amp: { canonicalBase: '' },
basePath: '',
sassOptions: {},
trailingSlash: false,
i18n: null,
productionBrowserSourceMaps: false,
excludeDefaultMomentLocales: true,
serverRuntimeConfig: {},
publicRuntimeConfig: {},
reactProductionProfiling: false,
reactStrictMode: true,
reactMaxHeadersLength: 6000,
httpAgentOptions: { keepAlive: true },
logging: {},
expireTime: 31536000,
staticPageGenerationTimeout: 60,
output: 'standalone',
modularizeImports: {
'@mui/icons-material': { transform: '@mui/icons-material/{{member}}' },
'lodash': { transform: 'lodash/{{member}}' },
},
outputFileTracingRoot: process.cwd(),
experimental: {
optimizeCss: true,
optimizePackageImports: [
'lucide-react',
'date-fns',
'lodash-es',
'ramda',
'antd',
'react-bootstrap',
'ahooks',
'@ant-design/icons',
'@headlessui/react',
'@headlessui-float/react',
'@heroicons/react/20/solid',
'@heroicons/react/24/solid',
'@heroicons/react/24/outline',
'@visx/visx',
'@tremor/react',
'rxjs',
'@mui/material',
'@mui/icons-material',
'recharts',
'react-use',
'framer-motion',
'@radix-ui/react-icons',
],
},
};
// Serialize config for Next.js
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig);
// Metrics tracking
const metrics = {
startTime: Date.now(),
requests: { total: 0, success: 0, error: 0 },
activeConnections: 0,
};
// Request logging middleware
function logRequest(req, res, startTime) {
const duration = Date.now() - startTime;
const logEntry = {
timestamp: new Date().toISOString(),
method: req.method,
url: req.url,
status: res.statusCode,
duration: `${duration}ms`,
userAgent: req.headers['user-agent'],
ip: req.headers['x-forwarded-for'] || req.socket.remoteAddress,
};
// Log errors with more detail
if (res.statusCode >= 400) {
console.error('[REQUEST ERROR]', JSON.stringify(logEntry));
metrics.requests.error++;
} else {
console.log('[REQUEST]', JSON.stringify(logEntry));
metrics.requests.success++;
}
metrics.requests.total++;
}
// Security headers middleware
function setSecurityHeaders(res) {
res.setHeader('X-DNS-Prefetch-Control', 'on');
res.setHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload');
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
}
// Health check handler
function healthCheck(req, res) {
const uptime = Date.now() - metrics.startTime;
const health = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: `${Math.floor(uptime / 1000)}s`,
version: process.env.npm_package_version || '2.0.0',
nodejs: process.version,
memory: process.memoryUsage(),
metrics: {
requests: metrics.requests,
activeConnections: metrics.activeConnections,
},
};
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(health, null, 2));
}
// Metrics endpoint for monitoring
function metricsEndpoint(req, res) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
...metrics,
memory: process.memoryUsage(),
cpu: process.cpuUsage(),
uptime: process.uptime(),
}, null, 2));
}
// Main server startup
async function startServer() {
const { startServer: startNextServer } = require('next/dist/server/lib/start-server');
// Validate keep-alive timeout
let keepAliveTimeout = config.keepAliveTimeout;
if (
Number.isNaN(keepAliveTimeout) ||
!Number.isFinite(keepAliveTimeout) ||
keepAliveTimeout < 0
) {
keepAliveTimeout = undefined;
}
console.log(`
╔══════════════════════════════════════════════════════════════╗
β•‘ DeepStudio Pro - Starting Production Server β•‘
β•‘ Built with anycoder β†’ https://huggingface.co/spaces/akhaliq/anycoder β•‘
╠══════════════════════════════════════════════════════════════╣
Port: ${config.port}
Hostname: ${config.hostname}
Node Env: ${process.env.NODE_ENV}
Node Ver: ${process.version}
Start Time: ${new Date().toISOString()}
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
`);
try {
// Start the Next.js server
const server = await startNextServer({
dir,
isDev: false,
config: nextConfig,
hostname: config.hostname,
port: config.port,
allowRetry: false,
keepAliveTimeout,
});
// Get the underlying HTTP server to add custom middleware
const httpServer = server.server;
// Track connections for graceful shutdown
httpServer.on('connection', (socket) => {
metrics.activeConnections++;
socket.on('close', () => {
metrics.activeConnections--;
});
});
// Custom request handling for health checks and metrics
const originalHandler = httpServer.listeners('request')[0];
httpServer.removeAllListeners('request');
httpServer.on('request', (req, res) => {
const startTime = Date.now();
// Set security headers on all responses
setSecurityHeaders(res);
// Intercept health check requests
const parsedUrl = parse(req.url, true);
if (parsedUrl.pathname === '/api/health') {
healthCheck(req, res);
return;
}
// Metrics endpoint (basic auth in production recommended)
if (parsedUrl.pathname === '/api/metrics') {
metricsEndpoint(req, res);
return;
}
// Log response when finished
res.on('finish', () => logRequest(req, res, startTime));
// Pass to Next.js handler
originalHandler(req, res);
});
// Graceful shutdown handling
const shutdown = (signal) => {
console.log(`\n[SHUTDOWN] Received ${signal}. Starting graceful shutdown...`);
console.log(`[SHUTDOWN] Active connections: ${metrics.activeConnections}`);
// Stop accepting new connections
httpServer.close(() => {
console.log('[SHUTDOWN] HTTP server closed');
process.exit(0);
});
// Force shutdown after timeout
setTimeout(() => {
console.error('[SHUTDOWN] Forced shutdown after timeout');
process.exit(1);
}, 30000);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
// Handle uncaught errors
process.on('uncaughtException', (err) => {
console.error('[FATAL] Uncaught exception:', err);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('[FATAL] Unhandled rejection at:', promise, 'reason:', reason);
process.exit(1);
});
console.log(`[READY] Server running at http://${config.hostname}:${config.port}`);
return server;
} catch (err) {
console.error('[FATAL] Failed to start server:', err);
process.exit(1);
}
}
// Start the server
startServer();