mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-14 21:29:34 +00:00
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
/**
|
|
* Shared Python-runtime probes. Used by Kokoro synthesis (which must
|
|
* actually `import` a module before using it) and by the `auth status` /
|
|
* `doctor` readiness checks (which only need to know whether a module is
|
|
* installed, cheaply, without paying the cost of importing heavy packages
|
|
* like torch).
|
|
*/
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
|
|
/** Locate a Python 3: `HYPERFRAMES_PYTHON` env override first, then PATH. */
|
|
export function findPython(): string | undefined {
|
|
const override = process.env.HYPERFRAMES_PYTHON;
|
|
if (override) {
|
|
try {
|
|
const version = execFileSync(override, ["--version"], {
|
|
encoding: "utf-8",
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
timeout: 5000,
|
|
});
|
|
if (/Python 3/.test(version)) return override;
|
|
} catch {
|
|
// fall through to the PATH probe
|
|
}
|
|
}
|
|
for (const name of ["python3", "python"]) {
|
|
try {
|
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
const output = execFileSync(cmd, [name], {
|
|
encoding: "utf-8",
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
timeout: 5000,
|
|
});
|
|
const first = output
|
|
.split(/\r?\n/)
|
|
.map((s) => s.trim())
|
|
.find(Boolean);
|
|
if (!first) continue;
|
|
|
|
// Verify it's Python 3
|
|
const version = execFileSync(first, ["--version"], {
|
|
encoding: "utf-8",
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
timeout: 5000,
|
|
}).trim();
|
|
|
|
if (version.includes("Python 3")) return first;
|
|
} catch {
|
|
// not found or not Python 3
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/** True if `import <pkg>` succeeds — actually executes the module. */
|
|
export function hasPythonPackage(python: string, pkg: string): boolean {
|
|
try {
|
|
execFileSync(python, ["-c", `import ${pkg}`], {
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
timeout: 10_000,
|
|
});
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* True if every module is installed, checked via `importlib.util.find_spec`
|
|
* so heavy packages (torch) are never imported — fast enough for a preflight.
|
|
* Returns false when no Python 3 is found.
|
|
*/
|
|
export function hasPythonModules(modules: string[]): boolean {
|
|
const python = findPython();
|
|
if (!python) return false;
|
|
const list = JSON.stringify(modules);
|
|
const probe = `import importlib.util,sys; sys.exit(0 if all(importlib.util.find_spec(m) for m in ${list}) else 1)`;
|
|
try {
|
|
execFileSync(python, ["-c", probe], {
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
timeout: 10_000,
|
|
});
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|