nai-aclab 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/nai-artist-lab.js +47 -15
- package/launcher.py +31 -3
- package/package.json +1 -1
package/bin/nai-artist-lab.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { spawn } = require("child_process");
|
|
3
|
+
const { spawn, spawnSync } = require("child_process");
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
@@ -58,19 +58,60 @@ function pythonCandidates() {
|
|
|
58
58
|
return candidates;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
function versionParts(text) {
|
|
62
|
+
const match = String(text || "").match(/(\d+)\.(\d+)\.(\d+)/);
|
|
63
|
+
if (!match) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return match.slice(1).map((part) => Number(part));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function supportsPython(candidate) {
|
|
70
|
+
const probe = spawnSync(
|
|
71
|
+
candidate.command,
|
|
72
|
+
[
|
|
73
|
+
...candidate.args,
|
|
74
|
+
"-c",
|
|
75
|
+
"import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')",
|
|
76
|
+
],
|
|
77
|
+
{
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
80
|
+
windowsHide: true,
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (probe.error || probe.status !== 0) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const parts = versionParts(probe.stdout);
|
|
89
|
+
if (!parts) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const [major, minor] = parts;
|
|
94
|
+
return major > 3 || (major === 3 && minor >= 10);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function choosePython() {
|
|
98
|
+
return pythonCandidates().find((candidate) => supportsPython(candidate));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function runWithCandidate(candidate) {
|
|
102
|
+
if (!candidate) {
|
|
103
|
+
console.error("Python 3.10 or newer was not found.");
|
|
104
|
+
console.error("Install Python from https://www.python.org/downloads/ and run npx nai-aclab again.");
|
|
64
105
|
process.exit(1);
|
|
65
106
|
}
|
|
66
107
|
|
|
67
|
-
const candidate = candidates[index];
|
|
68
108
|
const env = {
|
|
69
109
|
...process.env,
|
|
70
110
|
NAI_ARTIST_LAB_USER_DIR: userDataDir(),
|
|
71
111
|
};
|
|
72
112
|
|
|
73
113
|
fs.mkdirSync(env.NAI_ARTIST_LAB_USER_DIR, { recursive: true });
|
|
114
|
+
console.log(`Starting NAI Artist Combination Lab ${packageJson.version}...`);
|
|
74
115
|
|
|
75
116
|
const child = spawn(candidate.command, [...candidate.args, launcherPath], {
|
|
76
117
|
cwd: rootDir,
|
|
@@ -79,21 +120,12 @@ function runWithCandidate(candidates, index) {
|
|
|
79
120
|
windowsHide: false,
|
|
80
121
|
});
|
|
81
122
|
|
|
82
|
-
let failedToStart = false;
|
|
83
123
|
child.on("error", (error) => {
|
|
84
|
-
failedToStart = true;
|
|
85
|
-
if (error.code === "ENOENT") {
|
|
86
|
-
runWithCandidate(candidates, index + 1);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
124
|
console.error(error.message);
|
|
90
125
|
process.exit(1);
|
|
91
126
|
});
|
|
92
127
|
|
|
93
128
|
child.on("exit", (code, signal) => {
|
|
94
|
-
if (failedToStart) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
129
|
if (signal) {
|
|
98
130
|
process.kill(process.pid, signal);
|
|
99
131
|
return;
|
|
@@ -112,4 +144,4 @@ if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
|
112
144
|
process.exit(0);
|
|
113
145
|
}
|
|
114
146
|
|
|
115
|
-
runWithCandidate(
|
|
147
|
+
runWithCandidate(choosePython());
|
package/launcher.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import socket
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
4
7
|
import webbrowser
|
|
5
8
|
from http.server import ThreadingHTTPServer
|
|
6
9
|
|
|
@@ -21,14 +24,39 @@ def find_port(start: int = 8777) -> int:
|
|
|
21
24
|
raise RuntimeError("No available local port found.")
|
|
22
25
|
|
|
23
26
|
|
|
27
|
+
def open_browser(url: str) -> bool:
|
|
28
|
+
if os.environ.get("NAI_ARTIST_LAB_NO_BROWSER", "").lower() in {"1", "true", "yes"}:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
if sys.platform.startswith("win"):
|
|
33
|
+
os.startfile(url) # type: ignore[attr-defined]
|
|
34
|
+
return True
|
|
35
|
+
if sys.platform == "darwin":
|
|
36
|
+
subprocess.Popen(["open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
37
|
+
return True
|
|
38
|
+
subprocess.Popen(["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
39
|
+
return True
|
|
40
|
+
except Exception:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
return bool(webbrowser.open(url, new=2))
|
|
45
|
+
except Exception:
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
|
|
24
49
|
def main() -> None:
|
|
25
50
|
port = find_port()
|
|
26
51
|
server = ThreadingHTTPServer(("127.0.0.1", port), Handler)
|
|
27
52
|
url = f"http://127.0.0.1:{port}/"
|
|
28
53
|
|
|
29
|
-
|
|
30
|
-
print(
|
|
31
|
-
|
|
54
|
+
print(f"{APP_NAME} is running at {url}", flush=True)
|
|
55
|
+
print("Keep this terminal open while using the app. Press Ctrl+C to stop.", flush=True)
|
|
56
|
+
if open_browser(url):
|
|
57
|
+
print("Opening your browser now...", flush=True)
|
|
58
|
+
else:
|
|
59
|
+
print("Could not open a browser automatically. Copy and paste the URL above into your browser.", flush=True)
|
|
32
60
|
|
|
33
61
|
try:
|
|
34
62
|
server.serve_forever()
|