UNPKG

@kaifronsdal/transcript-viewer

Version:

A web-based viewer for AI conversation transcripts with rollback support

190 lines (158 loc) • 6.05 kB
#!/usr/bin/env node import { exec } from 'child_process'; import { fileURLToPath } from 'url'; import { dirname, join, resolve } from 'path'; import { existsSync } from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packageRoot = join(__dirname, '..'); const buildDir = join(packageRoot, 'build'); // Parse command line arguments const args = process.argv.slice(2); const forceRebuild = args.includes('--force-rebuild') || args.includes('-f'); const showHelp = args.includes('--help') || args.includes('-h'); // Parse transcript directory argument let transcriptDir = null; const dirIndex = args.findIndex(arg => arg === '--dir' || arg === '-d'); if (dirIndex !== -1 && args[dirIndex + 1]) { transcriptDir = resolve(args[dirIndex + 1]); } else { // Check for --dir=path format const dirArg = args.find(arg => arg.startsWith('--dir=')); if (dirArg) { transcriptDir = resolve(dirArg.split('=')[1]); } } // Parse host argument let host = null; const hostIndex = args.findIndex(arg => arg === '--host'); if (hostIndex !== -1 && args[hostIndex + 1]) { host = args[hostIndex + 1]; } else { // Check for --host=value format const hostArg = args.find(arg => arg.startsWith('--host=')); if (hostArg) { host = hostArg.split('=')[1]; } } // Parse port argument let port = null; const portIndex = args.findIndex(arg => arg === '--port' || arg === '-p'); if (portIndex !== -1 && args[portIndex + 1]) { port = parseInt(args[portIndex + 1]); } else { // Check for --port=value format const portArg = args.find(arg => arg.startsWith('--port=')); if (portArg) { port = parseInt(portArg.split('=')[1]); } } if (showHelp) { console.log(`transcript-viewer - A web-based viewer for AI conversation transcripts USAGE: transcript-viewer [OPTIONS] OPTIONS: -d, --dir <PATH> Specify the transcript directory to load [default: ./transcripts] --host <HOST> Specify the host to bind to [default: localhost] Use 0.0.0.0 for RunPod/Docker environments -p, --port <PORT> Specify the port to bind to [default: 3000] -f, --force-rebuild Force rebuild the application even if build exists -h, --help Print help information EXAMPLES: transcript-viewer Start with default directory (./transcripts) transcript-viewer --dir ./my-transcripts Start with custom directory transcript-viewer -d /path/to/transcripts Start with custom directory (short form) transcript-viewer --host 0.0.0.0 --port 8080 Start accessible from all interfaces on port 8080 (RunPod compatible) transcript-viewer --force-rebuild Force rebuild and start RUNPOD USAGE: transcript-viewer --host 0.0.0.0 --port 8080 --dir /workspace/transcripts Recommended settings for RunPod deployment `); process.exit(0); } console.log('šŸš€ Starting Transcript Viewer...'); if (transcriptDir) { if (!existsSync(transcriptDir)) { console.error(`āŒ Error: Transcript directory does not exist: ${transcriptDir}`); process.exit(1); } console.log(`šŸ“ Using transcript directory: ${transcriptDir}`); } else { const defaultPath = resolve(process.cwd(), 'transcripts'); console.log(`šŸ“ Using default transcript directory: ${defaultPath}`); console.log(`šŸ’” Tip: Use --dir <path> to specify a different directory`); } // Configure host and port const finalHost = host || process.env.HOST || 'localhost'; const finalPort = port || parseInt(process.env.PORT || '3000'); console.log(`🌐 Server will bind to: ${finalHost}:${finalPort}`); if (finalHost === '0.0.0.0') { console.log(`šŸš€ RunPod/Docker mode: Server will be accessible from all interfaces`); } // Check if build directory exists and if we should force rebuild if (!existsSync(buildDir) || forceRebuild) { if (forceRebuild) { console.log('šŸ”„ Force rebuilding application...'); } else { console.log('šŸ“¦ Building application...'); } exec('npm run build', { cwd: packageRoot }, (error, stdout, stderr) => { if (error) { console.error('āŒ Build failed:', error); process.exit(1); } // console.log(stdout); // console.log(stderr); console.log('šŸ—ļø Build completed'); startServer(); }); } else { startServer(); } function startServer() { console.log('🌐 Starting server...'); // Set up environment variables const env = { ...process.env }; if (transcriptDir) { env.TRANSCRIPT_DIR = transcriptDir; } else { // If no directory specified, use ./transcripts relative to where the user ran the command env.TRANSCRIPT_DIR = resolve(process.cwd(), 'transcripts'); } // Build the start command with host and port const startCommand = `vite preview --host ${finalHost} --port ${finalPort}`; const server = exec(startCommand, { cwd: packageRoot, env }); server.stdout.on('data', (data) => { console.log(data.toString()); // Look for the local URL in the output const urlMatch = data.toString().match(/Listening on (http:\/\/[^\s]+)/); if (urlMatch) { console.log('\nāœ… Transcript Viewer is running!'); console.log(`šŸ”— Open your browser to: ${urlMatch[1]}`); // Show RunPod-specific instructions if binding to all interfaces if (finalHost === '0.0.0.0') { console.log(`šŸš€ RunPod: Your service should be accessible via the RunPod public URL`); console.log(`šŸ“ Make sure port ${finalPort} is exposed in your RunPod configuration`); } console.log('\nšŸ’” To stop the server, press Ctrl+C'); } }); server.stderr.on('data', (data) => { console.error(data.toString()); }); server.on('close', (code) => { console.log(`\nšŸ‘‹ Server stopped with code ${code}`); }); // Handle Ctrl+C gracefully process.on('SIGINT', () => { console.log('\nšŸ›‘ Stopping server...'); server.kill('SIGINT'); process.exit(0); }); }