Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | import { spawn } from 'child_process' import path from 'path' import { ensureVenvReady, isPlatformSupported, PYTHON_ENV, TRAINING_PYTHON, TRAINING_SCRIPTS_DIR, } from '../config' import { withAuth } from '@/lib/auth/withAuth' // Force dynamic rendering - this route runs system commands at runtime export const dynamic = 'force-dynamic' /** * Hardware detection result from Python/TensorFlow */ interface HardwareInfo { available: boolean device: string deviceName: string deviceType: string details: Record<string, unknown> error: string | null } /** * Cache the hardware info since it doesn't change */ let cachedHardwareInfo: HardwareInfo | null = null let cacheTimestamp = 0 const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour /** * GET /api/vision-training/hardware * * Detects and returns the hardware that will be used for training. * Runs a Python script that queries TensorFlow for available devices. */ export const GET = withAuth( async () => { // Check platform support first - don't even try to set up venv on unsupported platforms const platformCheck = isPlatformSupported() if (!platformCheck.supported) { const unsupportedResult: HardwareInfo = { available: false, device: 'unsupported', deviceName: 'Platform Not Supported', deviceType: 'unsupported', details: { platform: process.platform, arch: process.arch, }, error: platformCheck.reason || 'This platform does not support TensorFlow training', } return new Response(JSON.stringify(unsupportedResult), { status: 200, headers: { 'Content-Type': 'application/json' }, }) } // Return cached result if valid const now = Date.now() if (cachedHardwareInfo && now - cacheTimestamp < CACHE_TTL_MS) { return new Response(JSON.stringify(cachedHardwareInfo), { status: 200, headers: { 'Content-Type': 'application/json' }, }) } try { // Ensure venv is set up (lazy, cached) const setup = await ensureVenvReady() if (!setup.success) { return new Response( JSON.stringify({ available: false, device: 'unknown', deviceName: 'Setup Failed', deviceType: 'unknown', details: {}, error: setup.error || 'Failed to set up Python environment', hint: 'Check server logs for details', }), { status: 200, headers: { 'Content-Type': 'application/json' } } ) } const cwd = path.resolve(process.cwd()) const scriptPath = path.join(TRAINING_SCRIPTS_DIR, 'detect_hardware.py') const result = await new Promise<HardwareInfo>((resolve, reject) => { let stdout = '' let stderr = '' let hasError = false // Use shared Python config - same as training uses const childProcess = spawn(TRAINING_PYTHON, [scriptPath], { cwd, env: PYTHON_ENV, }) childProcess.stdout?.on('data', (data: Buffer) => { stdout += data.toString() }) childProcess.stderr?.on('data', (data: Buffer) => { stderr += data.toString() }) childProcess.on('error', (error) => { hasError = true reject(new Error(`Failed to spawn python3: ${error.message}`)) }) childProcess.on('close', (code) => { if (hasError) return // Already rejected if (code === 0) { try { const parsed = JSON.parse(stdout.trim()) resolve(parsed) } catch { reject(new Error(`Failed to parse hardware info: ${stdout}`)) } } else { const errorInfo = stderr || stdout || 'No output' reject(new Error(`Hardware detection failed (code ${code}): ${errorInfo}`)) } }) // Timeout after 30 seconds setTimeout(() => { if (!hasError) { childProcess.kill() reject(new Error('Hardware detection timed out after 30 seconds')) } }, 30000) }) // Cache successful result cachedHardwareInfo = result cacheTimestamp = now return new Response(JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json' }, }) } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error' // Check for common issues let hint = '' if (errorMessage.includes('ENOENT') || errorMessage.includes('python3')) { hint = 'Python 3 is not installed or not in PATH' } else if (errorMessage.includes('TensorFlow not installed')) { hint = 'Install TensorFlow: pip install tensorflow' } return new Response( JSON.stringify({ available: false, device: 'unknown', deviceName: 'Detection Failed', deviceType: 'unknown', details: {}, error: errorMessage, hint, }), { status: 200, // Return 200 even on detection failure so UI can show the error headers: { 'Content-Type': 'application/json' }, } ) } }, { role: 'admin' } ) |