@mcptoolshop/style-dataset-lab 3.0.0 → 3.0.1
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/CHANGELOG.md +68 -15
- package/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +71 -0
- package/README.md +46 -1
- package/SECURITY.md +6 -5
- package/bin/sdlab.js +281 -62
- package/lib/adapters/diffusers-lora.js +7 -2
- package/lib/adapters/generic-image-caption.js +6 -1
- package/lib/args.js +200 -13
- package/lib/batch-compiler.js +7 -3
- package/lib/batch-runs.js +100 -31
- package/lib/batch-sheet-render.js +5 -2
- package/lib/brief-compiler.js +38 -11
- package/lib/card.js +11 -4
- package/lib/comfyui.js +100 -6
- package/lib/config.js +68 -3
- package/lib/deprecation.js +1 -1
- package/lib/eval-pack.js +94 -4
- package/lib/eval-runs.js +42 -3
- package/lib/export.js +144 -34
- package/lib/implementation-packs.js +15 -1
- package/lib/log.js +41 -4
- package/lib/paths.js +41 -3
- package/lib/refine-briefs.js +16 -9
- package/lib/reingest-selected.js +14 -3
- package/lib/reingest.js +15 -1
- package/lib/run-summary.js +3 -2
- package/lib/runtime-runs.js +59 -9
- package/lib/selections.js +54 -2
- package/lib/snapshot.js +100 -7
- package/lib/split.js +175 -17
- package/lib/training-manifests.js +17 -3
- package/lib/training-packages.js +28 -14
- package/package.json +8 -2
- package/scripts/batch-generate.js +16 -7
- package/scripts/batch-sheet.js +3 -3
- package/scripts/batch-show.js +3 -3
- package/scripts/brief-compile.js +8 -8
- package/scripts/brief-show.js +4 -3
- package/scripts/canon-bind.js +7 -9
- package/scripts/card.js +22 -25
- package/scripts/compare.js +38 -33
- package/scripts/critique-show.js +3 -3
- package/scripts/critique.js +3 -3
- package/scripts/curate.js +91 -46
- package/scripts/doctor.js +3 -5
- package/scripts/eligibility.js +17 -14
- package/scripts/eval-pack.js +13 -11
- package/scripts/eval-run.js +30 -29
- package/scripts/export.js +27 -31
- package/scripts/generate-controlnet.js +31 -17
- package/scripts/generate-identity.js +37 -20
- package/scripts/generate-ipadapter.js +22 -16
- package/scripts/generate.js +68 -13
- package/scripts/implementation-pack.js +19 -14
- package/scripts/init.js +115 -17
- package/scripts/painterly.js +8 -10
- package/scripts/refine.js +3 -3
- package/scripts/reingest-selected.js +3 -3
- package/scripts/reingest.js +33 -20
- package/scripts/run-generate.js +4 -4
- package/scripts/run-list.js +3 -3
- package/scripts/run-show.js +3 -3
- package/scripts/select.js +5 -4
- package/scripts/selection-show.js +3 -3
- package/scripts/snapshot.js +22 -24
- package/scripts/split.js +26 -31
- package/scripts/training-manifest.js +29 -24
- package/scripts/training-package.js +24 -20
- package/scripts/training-profile.js +13 -8
- package/scripts/workflow-list.js +2 -2
- package/scripts/workflow-show.js +4 -3
- package/templates/domains/architecture/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/architecture/terminology.json +10 -8
- package/templates/domains/character-design/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/character-design/project.json +4 -2
- package/templates/domains/creature-design/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/creature-design/project.json +4 -2
- package/templates/domains/creature-design/terminology.json +1 -0
- package/templates/domains/game-art/inputs/prompts/example-wave.json +37 -0
- package/templates/domains/game-art/project.json +4 -2
- package/templates/domains/vehicle-mech/inputs/prompts/example-wave.json +37 -0
- package/templates/domains/vehicle-mech/project.json +4 -2
- package/scripts/bulk-curate-wave2-5.js +0 -138
- package/scripts/bulk-curate-waves11-18.js +0 -413
- package/scripts/curate-wave25.js +0 -209
- package/scripts/migrate-records.js +0 -141
- package/templates/inputs/prompts/example-wave.json +0 -27
package/scripts/split.js
CHANGED
|
@@ -10,43 +10,45 @@
|
|
|
10
10
|
* sdlab split audit <split-id> [--project <name>]
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { readFile } from 'node:fs/promises';
|
|
14
13
|
import { join } from 'node:path';
|
|
15
|
-
import { getProjectName } from '../lib/args.js';
|
|
14
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
16
15
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
17
16
|
import { loadSplitProfile } from '../lib/config.js';
|
|
17
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
18
18
|
import { listSnapshots } from '../lib/snapshot.js';
|
|
19
19
|
import { createSplit, loadSplit, loadSplitAudit, listSplits } from '../lib/split.js';
|
|
20
20
|
|
|
21
21
|
export async function run(argv = process.argv.slice(2)) {
|
|
22
|
-
const
|
|
22
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
23
|
+
flags: {
|
|
24
|
+
project: { type: 'string' },
|
|
25
|
+
snapshot: { type: 'string' },
|
|
26
|
+
profile: { type: 'string' },
|
|
27
|
+
'dry-run': { type: 'boolean', default: false },
|
|
28
|
+
},
|
|
29
|
+
deprecated: { game: 'project' },
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const projectName = flags.project || getProjectName(argv);
|
|
23
33
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
24
|
-
const subcommand =
|
|
25
|
-
const
|
|
34
|
+
const subcommand = positionals[0] || 'list';
|
|
35
|
+
const dryRun = flags['dry-run'] || flags.dryRun;
|
|
26
36
|
|
|
27
37
|
if (subcommand === 'build') {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const snapIdx = args.indexOf('--snapshot');
|
|
31
|
-
if (snapIdx >= 0) {
|
|
32
|
-
snapshotId = args[snapIdx + 1];
|
|
33
|
-
} else {
|
|
34
|
-
// Use latest snapshot
|
|
38
|
+
let snapshotId = flags.snapshot;
|
|
39
|
+
if (!snapshotId) {
|
|
35
40
|
const snapshots = await listSnapshots(projectRoot);
|
|
36
41
|
if (snapshots.length === 0) {
|
|
37
|
-
throw
|
|
42
|
+
throw inputError('INPUT_NO_SNAPSHOT', 'No snapshots found. Run: sdlab snapshot create');
|
|
38
43
|
}
|
|
39
44
|
snapshotId = snapshots[snapshots.length - 1].id;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
const
|
|
43
|
-
const profileId = profileIdx >= 0 ? args[profileIdx + 1] : null;
|
|
44
|
-
const profile = loadSplitProfile(projectRoot, profileId);
|
|
45
|
-
const dryRun = argv.includes('--dry-run');
|
|
47
|
+
const profile = loadSplitProfile(projectRoot, flags.profile);
|
|
46
48
|
|
|
47
49
|
console.log(`\x1b[1msdlab split build\x1b[0m — ${projectName}`);
|
|
48
50
|
console.log(` Snapshot: ${snapshotId}`);
|
|
49
|
-
console.log(` Profile: ${
|
|
51
|
+
console.log(` Profile: ${flags.profile || 'balanced-default (built-in)'}`);
|
|
50
52
|
console.log(` Strategy: ${profile.strategy}`);
|
|
51
53
|
console.log(` Ratios: ${profile.train_ratio}/${profile.val_ratio}/${profile.test_ratio}`);
|
|
52
54
|
console.log(` Seed: ${profile.seed}`);
|
|
@@ -60,7 +62,6 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
60
62
|
console.log(` Val: ${result.val}`);
|
|
61
63
|
console.log(` Test: ${result.test}`);
|
|
62
64
|
|
|
63
|
-
// Show audit summary
|
|
64
65
|
const audit = await loadSplitAudit(projectRoot, result.splitId);
|
|
65
66
|
console.log('');
|
|
66
67
|
if (audit.leakage_check.passed) {
|
|
@@ -86,8 +87,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
} else if (subcommand === 'show') {
|
|
89
|
-
const splitId =
|
|
90
|
-
if (!splitId) throw
|
|
90
|
+
const splitId = positionals[1] || positionals.find(a => a.startsWith('split-'));
|
|
91
|
+
if (!splitId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab split show <split-id>');
|
|
91
92
|
|
|
92
93
|
const manifest = await loadSplit(projectRoot, splitId);
|
|
93
94
|
console.log(`\x1b[1mSplit\x1b[0m — ${splitId}\n`);
|
|
@@ -112,13 +113,12 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
} else if (subcommand === 'audit') {
|
|
115
|
-
const splitId =
|
|
116
|
-
if (!splitId) throw
|
|
116
|
+
const splitId = positionals[1] || positionals.find(a => a.startsWith('split-'));
|
|
117
|
+
if (!splitId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab split audit <split-id>');
|
|
117
118
|
|
|
118
119
|
const audit = await loadSplitAudit(projectRoot, splitId);
|
|
119
120
|
console.log(`\x1b[1mSplit audit\x1b[0m — ${splitId}\n`);
|
|
120
121
|
|
|
121
|
-
// Leakage check
|
|
122
122
|
if (audit.leakage_check.passed) {
|
|
123
123
|
console.log(` \x1b[32m✓\x1b[0m Leakage check: PASSED`);
|
|
124
124
|
} else {
|
|
@@ -128,13 +128,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
// Family distribution
|
|
132
131
|
console.log(`\n Families: ${audit.family_count}`);
|
|
133
132
|
console.log(` Train: ${audit.families_per_split.train}`);
|
|
134
133
|
console.log(` Val: ${audit.families_per_split.val}`);
|
|
135
134
|
console.log(` Test: ${audit.families_per_split.test}`);
|
|
136
135
|
|
|
137
|
-
// Lane balance
|
|
138
136
|
console.log('\n Lane balance:');
|
|
139
137
|
console.log(` ${'Lane'.padEnd(20)} ${'Total'.padStart(6)} ${'Train%'.padStart(8)} ${'Val%'.padStart(8)} ${'Test%'.padStart(8)}`);
|
|
140
138
|
console.log(` ${'─'.repeat(52)}`);
|
|
@@ -143,14 +141,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
} else {
|
|
146
|
-
throw
|
|
144
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: build, list, show, audit`);
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
147
|
|
|
150
148
|
// Direct execution guard
|
|
151
149
|
if (process.argv[1] && (process.argv[1].endsWith('split.js') || process.argv[1].endsWith('split'))) {
|
|
152
|
-
run().catch(
|
|
153
|
-
console.error(err.message || err);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
});
|
|
150
|
+
run().catch(handleCliError);
|
|
156
151
|
}
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { getProjectName } from '../lib/args.js';
|
|
14
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
15
15
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
16
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
16
17
|
import { listExports } from '../lib/export.js';
|
|
17
18
|
import {
|
|
18
19
|
createTrainingManifest,
|
|
@@ -22,30 +23,34 @@ import {
|
|
|
22
23
|
} from '../lib/training-manifests.js';
|
|
23
24
|
|
|
24
25
|
export async function run(argv = process.argv.slice(2)) {
|
|
25
|
-
const
|
|
26
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
27
|
+
flags: {
|
|
28
|
+
project: { type: 'string' },
|
|
29
|
+
export: { type: 'string' },
|
|
30
|
+
profile: { type: 'string' },
|
|
31
|
+
adapter: { type: 'string' },
|
|
32
|
+
'base-model': { type: 'string' },
|
|
33
|
+
},
|
|
34
|
+
deprecated: { game: 'project' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const projectName = flags.project || getProjectName(argv);
|
|
26
38
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
27
|
-
const subcommand =
|
|
28
|
-
const args = argv.filter(a => a !== subcommand);
|
|
39
|
+
const subcommand = positionals.find(a => !a.startsWith('tm-')) || 'list';
|
|
29
40
|
|
|
30
41
|
if (subcommand === 'create') {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (exportIdx < 0) {
|
|
34
|
-
// Try latest export
|
|
42
|
+
let exportId = flags.export;
|
|
43
|
+
if (!exportId) {
|
|
35
44
|
const exports = await listExports(projectRoot);
|
|
36
|
-
if (exports.length === 0) throw
|
|
45
|
+
if (exports.length === 0) throw inputError('INPUT_NO_EXPORT', 'No exports found. Run: sdlab export build');
|
|
46
|
+
exportId = exports[exports.length - 1].id;
|
|
37
47
|
}
|
|
38
|
-
const exportId = exportIdx >= 0 ? args[exportIdx + 1] : (await listExports(projectRoot)).pop().id;
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const profileId = args[profileIdx + 1];
|
|
49
|
+
if (!flags.profile) throw inputError('INPUT_MISSING_FLAG', '--profile is required. Use: sdlab training-profile list');
|
|
50
|
+
const profileId = flags.profile;
|
|
43
51
|
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const baseModelIdx = args.indexOf('--base-model');
|
|
48
|
-
const baseModel = baseModelIdx >= 0 ? args[baseModelIdx + 1] : undefined;
|
|
52
|
+
const adapterTarget = flags.adapter;
|
|
53
|
+
const baseModel = flags['base-model'] || flags.baseModel;
|
|
49
54
|
|
|
50
55
|
console.log(`\x1b[1msdlab training-manifest create\x1b[0m — ${projectName}`);
|
|
51
56
|
console.log(` Export: ${exportId}`);
|
|
@@ -62,8 +67,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
62
67
|
console.log(` \x1b[32m✓\x1b[0m Manifest: ${result.manifestId}`);
|
|
63
68
|
|
|
64
69
|
} else if (subcommand === 'validate') {
|
|
65
|
-
const manifestId =
|
|
66
|
-
if (!manifestId) throw
|
|
70
|
+
const manifestId = positionals.find(a => a.startsWith('tm-'));
|
|
71
|
+
if (!manifestId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-manifest validate <manifest-id>');
|
|
67
72
|
|
|
68
73
|
console.log(`\x1b[1msdlab training-manifest validate\x1b[0m — ${manifestId}\n`);
|
|
69
74
|
const { valid, issues } = await validateTrainingManifest(projectRoot, manifestId);
|
|
@@ -78,8 +83,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
} else if (subcommand === 'show') {
|
|
81
|
-
const manifestId =
|
|
82
|
-
if (!manifestId) throw
|
|
86
|
+
const manifestId = positionals.find(a => a.startsWith('tm-'));
|
|
87
|
+
if (!manifestId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-manifest show <manifest-id>');
|
|
83
88
|
|
|
84
89
|
const manifest = await loadTrainingManifest(projectRoot, manifestId);
|
|
85
90
|
console.log(`\x1b[1mTraining manifest\x1b[0m — ${manifestId}\n`);
|
|
@@ -110,10 +115,10 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
} else {
|
|
113
|
-
throw
|
|
118
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: create, validate, show, list`);
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
if (process.argv[1] && (process.argv[1].endsWith('training-manifest.js') || process.argv[1].endsWith('training-manifest'))) {
|
|
118
|
-
run().catch(
|
|
123
|
+
run().catch(handleCliError);
|
|
119
124
|
}
|
|
@@ -10,48 +10,52 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
-
import { getProjectName } from '../lib/args.js';
|
|
13
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
14
14
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
15
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
15
16
|
import { listTrainingManifests } from '../lib/training-manifests.js';
|
|
16
17
|
import { buildTrainingPackage, listTrainingPackages, loadTrainingPackage } from '../lib/training-packages.js';
|
|
17
18
|
|
|
18
19
|
export async function run(argv = process.argv.slice(2)) {
|
|
19
|
-
const
|
|
20
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
21
|
+
flags: {
|
|
22
|
+
project: { type: 'string' },
|
|
23
|
+
manifest: { type: 'string' },
|
|
24
|
+
adapter: { type: 'string' },
|
|
25
|
+
copy: { type: 'boolean', default: false },
|
|
26
|
+
},
|
|
27
|
+
deprecated: { game: 'project' },
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const projectName = flags.project || getProjectName(argv);
|
|
20
31
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
21
|
-
const subcommand =
|
|
22
|
-
const args = argv.filter(a => a !== subcommand);
|
|
32
|
+
const subcommand = positionals.find(a => !a.startsWith('tp-') && !a.startsWith('tm-')) || 'list';
|
|
23
33
|
|
|
24
34
|
if (subcommand === 'build') {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const manifestIdx = args.indexOf('--manifest');
|
|
28
|
-
if (manifestIdx >= 0) {
|
|
29
|
-
manifestId = args[manifestIdx + 1];
|
|
30
|
-
} else {
|
|
35
|
+
let manifestId = flags.manifest;
|
|
36
|
+
if (!manifestId) {
|
|
31
37
|
const manifests = await listTrainingManifests(projectRoot);
|
|
32
|
-
if (manifests.length === 0) throw
|
|
38
|
+
if (manifests.length === 0) throw inputError('INPUT_NO_MANIFEST', 'No training manifests found. Run: sdlab training-manifest create');
|
|
33
39
|
manifestId = manifests[manifests.length - 1].id;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
const
|
|
37
|
-
const adapterOverride = adapterIdx >= 0 ? args[adapterIdx + 1] : undefined;
|
|
38
|
-
const copy = args.includes('--copy');
|
|
42
|
+
const adapterOverride = flags.adapter;
|
|
39
43
|
|
|
40
44
|
console.log(`\x1b[1msdlab training-package build\x1b[0m — ${projectName}`);
|
|
41
45
|
console.log(` Manifest: ${manifestId}`);
|
|
42
46
|
if (adapterOverride) console.log(` Adapter: ${adapterOverride}`);
|
|
43
|
-
console.log(` Images: ${copy ? 'copy' : 'symlink'}`);
|
|
47
|
+
console.log(` Images: ${flags.copy ? 'copy' : 'symlink'}`);
|
|
44
48
|
console.log('');
|
|
45
49
|
|
|
46
|
-
const result = await buildTrainingPackage(projectRoot, manifestId, { copy, adapterOverride });
|
|
50
|
+
const result = await buildTrainingPackage(projectRoot, manifestId, { copy: flags.copy, adapterOverride });
|
|
47
51
|
|
|
48
52
|
console.log(` \x1b[32m✓\x1b[0m Package: ${result.packageId}`);
|
|
49
53
|
console.log(` Records: ${result.records}`);
|
|
50
54
|
console.log(` Images: ${result.images}`);
|
|
51
55
|
|
|
52
56
|
} else if (subcommand === 'show') {
|
|
53
|
-
const packageId =
|
|
54
|
-
if (!packageId) throw
|
|
57
|
+
const packageId = positionals.find(a => a.startsWith('tp-'));
|
|
58
|
+
if (!packageId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-package show <package-id>');
|
|
55
59
|
|
|
56
60
|
const pkg = await loadTrainingPackage(projectRoot, packageId);
|
|
57
61
|
console.log(`\x1b[1mTraining package\x1b[0m — ${packageId}\n`);
|
|
@@ -75,10 +79,10 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
} else {
|
|
78
|
-
throw
|
|
82
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: build, show, list`);
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
if (process.argv[1] && (process.argv[1].endsWith('training-package.js') || process.argv[1].endsWith('training-package'))) {
|
|
83
|
-
run().catch(
|
|
87
|
+
run().catch(handleCliError);
|
|
84
88
|
}
|
|
@@ -9,15 +9,20 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { join } from 'node:path';
|
|
12
|
-
import { getProjectName } from '../lib/args.js';
|
|
12
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
13
13
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
14
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
14
15
|
import { listTrainingProfiles, loadTrainingProfile } from '../lib/training-profiles.js';
|
|
15
16
|
|
|
16
17
|
export async function run(argv = process.argv.slice(2)) {
|
|
17
|
-
const
|
|
18
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
19
|
+
flags: { project: { type: 'string' } },
|
|
20
|
+
deprecated: { game: 'project' },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const projectName = flags.project || getProjectName(argv);
|
|
18
24
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
19
|
-
const subcommand =
|
|
20
|
-
const args = argv.filter(a => a !== subcommand);
|
|
25
|
+
const subcommand = positionals[0] || 'list';
|
|
21
26
|
|
|
22
27
|
if (subcommand === 'list') {
|
|
23
28
|
const profiles = await listTrainingProfiles(projectRoot);
|
|
@@ -31,8 +36,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
} else if (subcommand === 'show') {
|
|
34
|
-
const profileId =
|
|
35
|
-
if (!profileId) throw
|
|
39
|
+
const profileId = positionals[1];
|
|
40
|
+
if (!profileId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-profile show <profile-id>');
|
|
36
41
|
|
|
37
42
|
const profile = await loadTrainingProfile(projectRoot, profileId);
|
|
38
43
|
console.log(`\x1b[1mTraining profile\x1b[0m — ${profileId}\n`);
|
|
@@ -54,10 +59,10 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
} else {
|
|
57
|
-
throw
|
|
62
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: list, show`);
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
if (process.argv[1] && (process.argv[1].endsWith('training-profile.js') || process.argv[1].endsWith('training-profile'))) {
|
|
62
|
-
run().catch(
|
|
67
|
+
run().catch(handleCliError);
|
|
63
68
|
}
|
package/scripts/workflow-list.js
CHANGED
|
@@ -15,13 +15,13 @@ import { listWorkflowProfiles } from '../lib/workflow-profiles.js';
|
|
|
15
15
|
export async function run(argv = process.argv.slice(2)) {
|
|
16
16
|
const { flags } = parseArgs(argv, {
|
|
17
17
|
flags: {
|
|
18
|
-
project: { type: 'string'
|
|
18
|
+
project: { type: 'string' },
|
|
19
19
|
json: { type: 'boolean' },
|
|
20
20
|
},
|
|
21
21
|
deprecated: { game: 'project' },
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
const projectName = flags.project;
|
|
24
|
+
const projectName = flags.project || getProjectName(argv);
|
|
25
25
|
const projectRoot = getProjectRoot(projectName);
|
|
26
26
|
const profiles = await listWorkflowProfiles(projectRoot);
|
|
27
27
|
|
package/scripts/workflow-show.js
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
* sdlab workflow show character-portrait-set --json
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { parseArgs } from '../lib/args.js';
|
|
11
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
12
12
|
import { getProjectRoot } from '../lib/paths.js';
|
|
13
13
|
import { getWorkflowProfile } from '../lib/workflow-profiles.js';
|
|
14
14
|
|
|
15
15
|
export async function run(argv = process.argv.slice(2)) {
|
|
16
16
|
const { flags, positionals } = parseArgs(argv, {
|
|
17
17
|
flags: {
|
|
18
|
-
project: { type: 'string'
|
|
18
|
+
project: { type: 'string' },
|
|
19
19
|
json: { type: 'boolean' },
|
|
20
20
|
},
|
|
21
21
|
positionals: ['workflowId'],
|
|
@@ -28,7 +28,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const projectName = flags.project || getProjectName(argv);
|
|
32
|
+
const projectRoot = getProjectRoot(projectName);
|
|
32
33
|
const profile = await getWorkflowProfile(projectRoot, workflowId);
|
|
33
34
|
|
|
34
35
|
if (flags.json) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"wave": "wave1",
|
|
3
|
+
"description": "Architecture — first wave. Subject IDs match this domain's lane id_patterns (ext_, int_, street_) so `sdlab generate` will route each candidate into the correct lane instead of default_lane.",
|
|
4
|
+
"defaults": {
|
|
5
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
6
|
+
"lora": { "name": "classipeintxl_v21.safetensors", "weight": 1.0 },
|
|
7
|
+
"width": 1024,
|
|
8
|
+
"height": 1024,
|
|
9
|
+
"steps": 8,
|
|
10
|
+
"cfg": 2.0,
|
|
11
|
+
"sampler": "dpmpp_sde",
|
|
12
|
+
"scheduler": "karras",
|
|
13
|
+
"negative": "photorealistic, photograph, 3d render, smooth CG, sharp photo detail"
|
|
14
|
+
},
|
|
15
|
+
"subjects": [
|
|
16
|
+
{
|
|
17
|
+
"id": "ext_landmark",
|
|
18
|
+
"variations": 2,
|
|
19
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR BUILDING — facade, elevation, architectural massing], painterly concept art, canvas grain"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "int_hall",
|
|
23
|
+
"variations": 2,
|
|
24
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR INTERIOR — hall, chamber, spatial atmosphere], painterly concept art, canvas grain"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "street_district",
|
|
28
|
+
"variations": 2,
|
|
29
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR STREETSCAPE — street-level view, urban fabric, district overview], painterly concept art, canvas grain"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
"null_faction_patterns": [],
|
|
9
9
|
"id_fallbacks": {},
|
|
10
10
|
"faction_context": {},
|
|
11
|
-
"training_profiles":
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
"training_profiles": [
|
|
12
|
+
{
|
|
13
|
+
"profile_id": "architecture-style",
|
|
14
|
+
"intended_use": "Architectural style LoRA for consistent worldbuilding",
|
|
15
|
+
"eligible_lanes": ["exterior", "interior", "streetscape"],
|
|
16
|
+
"minimum_review_threshold": 0.7,
|
|
17
|
+
"excluded_content": ["rejected"],
|
|
18
|
+
"export_format": "trl"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
19
21
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"wave": "wave1",
|
|
3
|
+
"description": "Character design — first wave. Subject IDs match this domain's lane id_patterns (portrait_, full_, expr_) so `sdlab generate` will route each candidate into the correct lane instead of default_lane.",
|
|
4
|
+
"defaults": {
|
|
5
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
6
|
+
"lora": { "name": "classipeintxl_v21.safetensors", "weight": 1.0 },
|
|
7
|
+
"width": 1024,
|
|
8
|
+
"height": 1024,
|
|
9
|
+
"steps": 8,
|
|
10
|
+
"cfg": 2.0,
|
|
11
|
+
"sampler": "dpmpp_sde",
|
|
12
|
+
"scheduler": "karras",
|
|
13
|
+
"negative": "photorealistic, photograph, 3d render, smooth CG, sharp photo detail"
|
|
14
|
+
},
|
|
15
|
+
"subjects": [
|
|
16
|
+
{
|
|
17
|
+
"id": "portrait_hero",
|
|
18
|
+
"variations": 2,
|
|
19
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR HERO — head and shoulders, face detail, expression], painterly concept art, canvas grain"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "full_body_hero",
|
|
23
|
+
"variations": 2,
|
|
24
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR HERO — full figure standing pose, costume, silhouette], painterly concept art, canvas grain"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "expr_hero_sheet",
|
|
28
|
+
"variations": 2,
|
|
29
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR HERO — emotion range sheet, consistent face across multiple expressions], painterly concept art, canvas grain"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
"domain": "character-design",
|
|
5
5
|
"version": "0.1.0",
|
|
6
6
|
"defaults": {
|
|
7
|
-
"checkpoint": "",
|
|
8
|
-
"loras": [
|
|
7
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
8
|
+
"loras": [
|
|
9
|
+
{ "name": "classipeintxl_v21.safetensors", "weight": 1.0 }
|
|
10
|
+
],
|
|
9
11
|
"width": 1024,
|
|
10
12
|
"height": 1024,
|
|
11
13
|
"steps": 8,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"wave": "wave1",
|
|
3
|
+
"description": "Creature design — first wave. Subject IDs match this domain's lane id_patterns (concept_, ortho_, action_) so `sdlab generate` will route each candidate into the correct lane instead of default_lane.",
|
|
4
|
+
"defaults": {
|
|
5
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
6
|
+
"lora": { "name": "classipeintxl_v21.safetensors", "weight": 1.0 },
|
|
7
|
+
"width": 1024,
|
|
8
|
+
"height": 1024,
|
|
9
|
+
"steps": 8,
|
|
10
|
+
"cfg": 2.0,
|
|
11
|
+
"sampler": "dpmpp_sde",
|
|
12
|
+
"scheduler": "karras",
|
|
13
|
+
"negative": "photorealistic, photograph, 3d render, smooth CG, sharp photo detail"
|
|
14
|
+
},
|
|
15
|
+
"subjects": [
|
|
16
|
+
{
|
|
17
|
+
"id": "concept_alpha",
|
|
18
|
+
"variations": 2,
|
|
19
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR CREATURE — initial concept, ideation exploration], painterly concept art, canvas grain"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "ortho_alpha",
|
|
23
|
+
"variations": 2,
|
|
24
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR CREATURE — turnaround model sheet, orthographic views for modelers], painterly concept art, canvas grain"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "action_alpha",
|
|
28
|
+
"variations": 2,
|
|
29
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR CREATURE — attack stance, locomotion study, movement key], painterly concept art, canvas grain"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
"version": "0.1.0",
|
|
6
6
|
"description": "Creature concept art — fantasy creatures, alien species, monsters, wildlife, and mythological beings.",
|
|
7
7
|
"defaults": {
|
|
8
|
-
"checkpoint": "",
|
|
9
|
-
"loras": [
|
|
8
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
9
|
+
"loras": [
|
|
10
|
+
{ "name": "classipeintxl_v21.safetensors", "weight": 1.0 }
|
|
11
|
+
],
|
|
10
12
|
"width": 1024,
|
|
11
13
|
"height": 1024,
|
|
12
14
|
"steps": 8,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"wave": "wave1",
|
|
3
|
+
"description": "Game art — first wave. Subject IDs match this domain's lane id_patterns (char_, env_, prop_, ship_) so `sdlab generate` will route each candidate into the correct lane instead of default_lane.",
|
|
4
|
+
"defaults": {
|
|
5
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
6
|
+
"lora": { "name": "classipeintxl_v21.safetensors", "weight": 1.0 },
|
|
7
|
+
"width": 1024,
|
|
8
|
+
"height": 1024,
|
|
9
|
+
"steps": 8,
|
|
10
|
+
"cfg": 2.0,
|
|
11
|
+
"sampler": "dpmpp_sde",
|
|
12
|
+
"scheduler": "karras",
|
|
13
|
+
"negative": "photorealistic, photograph, 3d render, smooth CG, sharp photo detail"
|
|
14
|
+
},
|
|
15
|
+
"subjects": [
|
|
16
|
+
{
|
|
17
|
+
"id": "char_hero",
|
|
18
|
+
"variations": 2,
|
|
19
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR CHARACTER — costume, faction identity, personal gear], painterly concept art, canvas grain"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "env_town",
|
|
23
|
+
"variations": 2,
|
|
24
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR ENVIRONMENT — town, dungeon, overworld location], painterly concept art, canvas grain"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "prop_key",
|
|
28
|
+
"variations": 2,
|
|
29
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR PROP — quest item, treasure, story-carrying object], painterly concept art, canvas grain"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "ship_flagship",
|
|
33
|
+
"variations": 2,
|
|
34
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR SHIP OR VEHICLE — exterior view, faction silhouette], painterly concept art, canvas grain"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
"domain": "game-art",
|
|
5
5
|
"version": "0.1.0",
|
|
6
6
|
"defaults": {
|
|
7
|
-
"checkpoint": "",
|
|
8
|
-
"loras": [
|
|
7
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
8
|
+
"loras": [
|
|
9
|
+
{ "name": "classipeintxl_v21.safetensors", "weight": 1.0 }
|
|
10
|
+
],
|
|
9
11
|
"width": 1024,
|
|
10
12
|
"height": 1024,
|
|
11
13
|
"steps": 8,
|