Initial clean project import

This commit is contained in:
cat-shark
2026-06-19 18:41:41 +08:00
commit a13b804c7a
1306 changed files with 220568 additions and 0 deletions
+186
View File
@@ -0,0 +1,186 @@
import { spawn } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
/**
* Python路径检测工具
* 支持在Windows、macOS、Linux等多个系统上检测Python
*/
let cachedPythonPath: string | null = null;
/**
* 获取系统中可用的Python可执行文件路径
* 优先级:
* 1. 环境变量 PYTHON_PATH
* 2. 环境变量 FUNASR_PYTHON_PATH
* 3. Windows特定位置
* 4. 系统PATH中的python3/python
*/
export function getPythonPath(): string {
// 如果已缓存,直接返回
if (cachedPythonPath) {
return cachedPythonPath;
}
// 1. 检查环境变量
if (process.env.PYTHON_PATH && fs.existsSync(process.env.PYTHON_PATH)) {
cachedPythonPath = process.env.PYTHON_PATH;
return cachedPythonPath;
}
if (process.env.FUNASR_PYTHON_PATH && fs.existsSync(process.env.FUNASR_PYTHON_PATH)) {
cachedPythonPath = process.env.FUNASR_PYTHON_PATH;
return cachedPythonPath;
}
// 2. Windows特定位置
if (process.platform === 'win32') {
const windowsPythonPaths = [
// 微软应用商店安装
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python312', 'python.exe'),
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python311', 'python.exe'),
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python310', 'python.exe'),
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python39', 'python.exe'),
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python38', 'python.exe'),
// 直接安装
'C:\\Python312\\python.exe',
'C:\\Python311\\python.exe',
'C:\\Python310\\python.exe',
'C:\\Python39\\python.exe',
'C:\\Python38\\python.exe',
// Anaconda/Miniconda
path.join(process.env.USERPROFILE || '', 'anaconda3', 'python.exe'),
path.join(process.env.USERPROFILE || '', 'miniconda3', 'python.exe'),
// WSL
path.join(process.env.USERPROFILE || '', 'AppData', 'Local', 'Microsoft', 'WindowsApps', 'python.exe'),
];
for (const pythonPath of windowsPythonPaths) {
if (fs.existsSync(pythonPath)) {
cachedPythonPath = pythonPath;
return cachedPythonPath;
}
}
}
// 3. macOS/Linux 特定位置
if (process.platform === 'darwin' || process.platform === 'linux') {
const unixPythonPaths = [
'/usr/bin/python3',
'/usr/bin/python',
'/usr/local/bin/python3',
'/usr/local/bin/python',
'/opt/homebrew/bin/python3', // M1/M2 Mac
path.join(process.env.HOME || '', '.pyenv', 'versions', 'default', 'bin', 'python'),
];
for (const pythonPath of unixPythonPaths) {
if (fs.existsSync(pythonPath)) {
cachedPythonPath = pythonPath;
return cachedPythonPath;
}
}
}
// 4. 默认尝试 python 或 python3
// 这会依赖系统 PATHWindows上可能不工作
if (process.platform === 'win32') {
cachedPythonPath = 'python';
} else {
cachedPythonPath = 'python3';
}
return cachedPythonPath;
}
/**
* 验证Python可执行文件是否可用
*/
export function isValidPythonPath(pythonPath: string): boolean {
return fs.existsSync(pythonPath);
}
/**
* 检查Python是否安装了特定的库
*/
export async function checkPythonModule(moduleName: string): Promise<boolean> {
return new Promise((resolve) => {
const pythonPath = getPythonPath();
const process = spawn(pythonPath, ['-m', 'pip', 'show', moduleName], {
stdio: ['pipe', 'pipe', 'pipe'],
shell: true
});
let stdout = '';
process.stdout.on('data', (data) => {
stdout += data.toString();
});
process.on('close', (code) => {
resolve(code === 0 && stdout.includes(`Name: ${moduleName}`));
});
process.on('error', () => {
resolve(false);
});
// 设置超时
setTimeout(() => {
process.kill();
resolve(false);
}, 5000);
});
}
/**
* 获取Python版本信息
*/
export async function getPythonVersion(): Promise<string | null> {
return new Promise((resolve) => {
const pythonPath = getPythonPath();
const process = spawn(pythonPath, ['--version'], {
stdio: ['pipe', 'pipe', 'pipe'],
shell: true
});
let stdout = '';
let stderr = '';
process.stdout.on('data', (data) => {
stdout += data.toString();
});
process.stderr.on('data', (data) => {
stderr += data.toString();
});
process.on('close', (code) => {
if (code === 0) {
resolve((stdout || stderr).trim());
} else {
resolve(null);
}
});
process.on('error', () => {
resolve(null);
});
// 设置超时
setTimeout(() => {
process.kill();
resolve(null);
}, 5000);
});
}
/**
* 清除缓存(用于测试)
*/
export function clearPythonPathCache(): void {
cachedPythonPath = null;
}