| 
									
										
										
										
											2024-05-19 05:24:32 +08:00
										 |  |  | const packages = [ | 
					
						
							| 
									
										
										
										
											2024-06-18 05:26:10 +08:00
										 |  |  | 	'micropip', | 
					
						
							|  |  |  | 	'packaging', | 
					
						
							| 
									
										
										
										
											2024-05-19 05:24:32 +08:00
										 |  |  | 	'requests', | 
					
						
							|  |  |  | 	'beautifulsoup4', | 
					
						
							|  |  |  | 	'numpy', | 
					
						
							|  |  |  | 	'pandas', | 
					
						
							|  |  |  | 	'matplotlib', | 
					
						
							|  |  |  | 	'scikit-learn', | 
					
						
							|  |  |  | 	'scipy', | 
					
						
							| 
									
										
										
										
											2024-05-20 00:46:43 +08:00
										 |  |  | 	'regex', | 
					
						
							| 
									
										
										
										
											2025-02-04 14:05:52 +08:00
										 |  |  | 	'sympy', | 
					
						
							|  |  |  | 	'tiktoken', | 
					
						
							| 
									
										
										
										
											2025-02-05 15:44:51 +08:00
										 |  |  | 	'seaborn', | 
					
						
							| 
									
										
										
										
											2025-06-09 00:26:07 +08:00
										 |  |  | 	'pytz', | 
					
						
							| 
									
										
										
										
											2025-07-09 03:28:43 +08:00
										 |  |  | 	'black', | 
					
						
							|  |  |  | 	'openai' | 
					
						
							| 
									
										
										
										
											2024-05-19 05:24:32 +08:00
										 |  |  | ]; | 
					
						
							| 
									
										
										
										
											2024-05-18 14:30:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import { loadPyodide } from 'pyodide'; | 
					
						
							| 
									
										
										
										
											2025-02-20 16:40:11 +08:00
										 |  |  | import { setGlobalDispatcher, ProxyAgent } from 'undici'; | 
					
						
							| 
									
										
										
										
											2024-06-18 05:26:10 +08:00
										 |  |  | import { writeFile, readFile, copyFile, readdir, rmdir } from 'fs/promises'; | 
					
						
							| 
									
										
										
										
											2024-05-18 14:30:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-20 16:40:11 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Loading network proxy configurations from the environment variables. | 
					
						
							|  |  |  |  * And the proxy config with lowercase name has the highest priority to use. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function initNetworkProxyFromEnv() { | 
					
						
							|  |  |  | 	// we assume all subsequent requests in this script are HTTPS:
 | 
					
						
							|  |  |  | 	// https://cdn.jsdelivr.net
 | 
					
						
							|  |  |  | 	// https://pypi.org
 | 
					
						
							|  |  |  | 	// https://files.pythonhosted.org
 | 
					
						
							|  |  |  | 	const allProxy = process.env.all_proxy || process.env.ALL_PROXY; | 
					
						
							|  |  |  | 	const httpsProxy = process.env.https_proxy || process.env.HTTPS_PROXY; | 
					
						
							|  |  |  | 	const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY; | 
					
						
							|  |  |  | 	const preferedProxy = httpsProxy || allProxy || httpProxy; | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * use only http(s) proxy because socks5 proxy is not supported currently: | 
					
						
							|  |  |  | 	 * @see https://github.com/nodejs/undici/issues/2224
 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (!preferedProxy || !preferedProxy.startsWith('http')) return; | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  | 	let preferedProxyURL; | 
					
						
							| 
									
										
										
										
											2025-02-20 16:40:11 +08:00
										 |  |  | 	try { | 
					
						
							|  |  |  | 		preferedProxyURL = new URL(preferedProxy).toString(); | 
					
						
							|  |  |  | 	} catch { | 
					
						
							|  |  |  | 		console.warn(`Invalid network proxy URL: "${preferedProxy}"`); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const dispatcher = new ProxyAgent({ uri: preferedProxyURL }); | 
					
						
							|  |  |  | 	setGlobalDispatcher(dispatcher); | 
					
						
							|  |  |  | 	console.log(`Initialized network proxy "${preferedProxy}" from env`); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-18 14:30:42 +08:00
										 |  |  | async function downloadPackages() { | 
					
						
							|  |  |  | 	console.log('Setting up pyodide + micropip'); | 
					
						
							| 
									
										
										
										
											2024-06-19 10:44:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	let pyodide; | 
					
						
							|  |  |  | 	try { | 
					
						
							|  |  |  | 		pyodide = await loadPyodide({ | 
					
						
							|  |  |  | 			packageCacheDir: 'static/pyodide' | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} catch (err) { | 
					
						
							|  |  |  | 		console.error('Failed to load Pyodide:', err); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-06-18 05:26:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	const packageJson = JSON.parse(await readFile('package.json')); | 
					
						
							| 
									
										
										
										
											2024-06-19 10:44:32 +08:00
										 |  |  | 	const pyodideVersion = packageJson.dependencies.pyodide.replace('^', ''); | 
					
						
							| 
									
										
										
										
											2024-06-18 05:26:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-18 05:28:56 +08:00
										 |  |  | 	try { | 
					
						
							|  |  |  | 		const pyodidePackageJson = JSON.parse(await readFile('static/pyodide/package.json')); | 
					
						
							| 
									
										
										
										
											2024-06-19 10:44:32 +08:00
										 |  |  | 		const pyodidePackageVersion = pyodidePackageJson.version.replace('^', ''); | 
					
						
							| 
									
										
										
										
											2024-06-18 05:28:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-19 10:44:32 +08:00
										 |  |  | 		if (pyodideVersion !== pyodidePackageVersion) { | 
					
						
							| 
									
										
										
										
											2024-06-18 05:28:56 +08:00
										 |  |  | 			console.log('Pyodide version mismatch, removing static/pyodide directory'); | 
					
						
							|  |  |  | 			await rmdir('static/pyodide', { recursive: true }); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-06-27 16:35:28 +08:00
										 |  |  | 	} catch (err) { | 
					
						
							|  |  |  | 		console.log('Pyodide package not found, proceeding with download.', err); | 
					
						
							| 
									
										
										
										
											2024-06-18 05:26:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-19 10:44:32 +08:00
										 |  |  | 	try { | 
					
						
							|  |  |  | 		console.log('Loading micropip package'); | 
					
						
							|  |  |  | 		await pyodide.loadPackage('micropip'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const micropip = pyodide.pyimport('micropip'); | 
					
						
							|  |  |  | 		console.log('Downloading Pyodide packages:', packages); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			for (const pkg of packages) { | 
					
						
							|  |  |  | 				console.log(`Installing package: ${pkg}`); | 
					
						
							|  |  |  | 				await micropip.install(pkg); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} catch (err) { | 
					
						
							|  |  |  | 			console.error('Package installation failed:', err); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		console.log('Pyodide packages downloaded, freezing into lock file'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			const lockFile = await micropip.freeze(); | 
					
						
							|  |  |  | 			await writeFile('static/pyodide/pyodide-lock.json', lockFile); | 
					
						
							|  |  |  | 		} catch (err) { | 
					
						
							|  |  |  | 			console.error('Failed to write lock file:', err); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} catch (err) { | 
					
						
							|  |  |  | 		console.error('Failed to load or install micropip:', err); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-18 14:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function copyPyodide() { | 
					
						
							|  |  |  | 	console.log('Copying Pyodide files into static directory'); | 
					
						
							|  |  |  | 	// Copy all files from node_modules/pyodide to static/pyodide
 | 
					
						
							|  |  |  | 	for await (const entry of await readdir('node_modules/pyodide')) { | 
					
						
							|  |  |  | 		await copyFile(`node_modules/pyodide/${entry}`, `static/pyodide/${entry}`); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-20 16:40:11 +08:00
										 |  |  | initNetworkProxyFromEnv(); | 
					
						
							| 
									
										
										
										
											2024-05-18 14:30:42 +08:00
										 |  |  | await downloadPackages(); | 
					
						
							|  |  |  | await copyPyodide(); |