第二步SAM模型接入

This commit is contained in:
Ukawka
2026-09-18 20:29:29 +08:00
parent 1a7b2f14a9
commit f095c28858
16 changed files with 788 additions and 26 deletions
+25 -4
View File
@@ -5,10 +5,12 @@ import {loadConfig, resolveStage, publicStage, samInfo} from '../lib/config.mjs'
import {requestJson} from '../providers/http.mjs';
import {runUnderstanding, runCompletionProbe} from '../stages/model-stage.mjs';
import {readImage} from '../lib/images.mjs';
import {runSegmentation} from '../stages/segmentation-stage.mjs';
const help = `模型接入与结构理解(新增模式,不调用旧拆件流程)
node pipeline.mjs --mode annotated-parts --reference image.png --out-dir output/run --stop-after understand
node tools/model-check.mjs --stage completion --image local.png --prompt-file task.txt --out-dir output/edit
node tools/model-check.mjs --stage segmentation --input-dir output/understand --out-dir output/segment --sam-dir F:/Study/SAM3
node tools/model-check.mjs --list-models
node tools/model-check.mjs --dry-run
@@ -23,11 +25,17 @@ const help = `模型接入与结构理解(新增模式,不调用旧拆件流
--resume 输入/配置/代码和产物哈希相同时复用
--parts-file FILE 离线读取已有 v1/v2 计划,做 Alpha 校验与种子生成,不请求模型
--python FILE ai-spine Conda 环境解释器(默认使用已激活环境)
--input-dir DIR 已完成的结构理解目录(SAM 阶段输入)
--sam-dir DIR 本地 SAM 根目录,包含 sam3 与 sam3.1checkpoint
--sam-code-dir DIR SAM 源码仓库目录覆盖
--sam-checkpoint FILE 本地权重路径覆盖
--sam-confidence FLOAT 模型候选分数阈值,默认 0.2
--sam-precision NAME bf16(默认)或 fp32
--image FILE 图片编辑输入,可重复;多图需配置 capabilities
--mask FILE 透明处可编辑的 RGBA PNG;需配置 capabilities
--dry-run 检查配置与本地输入,不请求模型、不生成产物
本轮 --stop-after 仅支持 understand。SAM 路径已配置,但分割/合并/导出尚未接入。`;
--stop-after 支持 understand / segment。SAM 在临时 GPU 子进程运行,完成后退出;补全合并/导出尚未接入。`;
export function parseOptions(argv) {
const options = {stage: 'understanding', imagePaths: []};
@@ -37,6 +45,8 @@ export function parseOptions(argv) {
['--understanding-protocol', 'understandingProtocol'], ['--output-mode', 'outputMode'],
['--stage', 'stage'], ['--mask', 'maskPath'], ['--prompt-file', 'promptFile'], ['--stop-after', 'stopAfter'],
['--mode', 'mode'], ['--python', 'python'], ['--stream', 'streamRaw'], ['--parts-file', 'partsFile'],
['--input-dir', 'inputDir'], ['--sam-dir', 'samDir'], ['--sam-code-dir', 'samCodeDir'],
['--sam-checkpoint', 'samCheckpoint'], ['--sam-confidence', 'samConfidence'], ['--sam-precision', 'samPrecision'],
]);
for (let i = 0; i < argv.length; i += 1) {
const flag = argv[i];
@@ -57,15 +67,22 @@ export function parseOptions(argv) {
export async function main(argv = process.argv.slice(2)) {
const options = parseOptions(argv);
if (options.help) { console.log(help); return; }
if (!['understanding', 'completion'].includes(options.stage)) throw new Error('--stage 仅支持 understanding 或 completion');
if (!['understanding', 'completion', 'segmentation'].includes(options.stage)) throw new Error('--stage 仅支持 understanding / completion / segmentation');
if (options.partsFile && (options.stage !== 'understanding' || options.listModels)) throw new Error('--parts-file 仅用于离线结构理解');
if (options.streamRaw !== undefined && !['true', 'false'].includes(options.streamRaw)) throw new Error('--stream 仅支持 true 或 false');
options.stream = options.streamRaw === undefined ? undefined : options.streamRaw === 'true';
if (options.mode && options.mode !== 'annotated-parts') throw new Error('新入口仅支持 --mode annotated-parts');
if (options.stopAfter && (options.stopAfter !== 'understand' || options.stage !== 'understanding')) {
throw new Error('本轮仅落地模型接入和结构理解;--stop-after 目前仅支持 understand');
if (options.stopAfter && (!['understand', 'segment'].includes(options.stopAfter) || options.stage === 'completion' || (options.stage === 'segmentation' && options.stopAfter !== 'segment'))) {
throw new Error('--stop-after 仅支持 understand / segment,且必须匹配阶段');
}
const loaded = loadConfig(options);
if (options.stage === 'segmentation' || (options.stopAfter === 'segment' && options.inputDir)) {
if (options.reference || options.partsFile || options.imagePaths.length || options.maskPath || options.promptFile || options.listModels) throw new Error('独立 SAM 阶段使用 --input-dir,不接受模型请求或编辑参数');
const result = await runSegmentation({...options, loaded});
if (!result.dryRun) console.log(`SAM 分割${result.reused ? '复用完成' : '完成'}:${path.join(result.out, 'report.html')}`);
return result;
}
if (options.inputDir) throw new Error('--input-dir 仅用于 SAM 分割阶段');
const overrides = options.stage === 'understanding'
? {model: options.understandingModel, protocol: options.understandingProtocol, outputMode: options.outputMode, stream: options.stream}
: {model: options.completionModel};
@@ -93,6 +110,10 @@ export async function main(argv = process.argv.slice(2)) {
console.log(options.partsFile ? '角色结构理解:离线计划几何校验' : `角色结构理解:${stage.model} (${stage.protocol})`);
result = await runUnderstanding({...options, loaded, stage});
console.log(`${result.reused ? '复用已校验产物' : '结构理解完成,语义待复核'}:${path.join(result.out, 'report.html')}`);
if (options.stopAfter === 'segment') {
result = await runSegmentation({...options, loaded, inputDir: result.out, outDir: path.join(result.out, 'segmentation')});
console.log(`SAM 分割完成:${path.join(result.out, 'report.html')}`);
}
} else {
if (options.reference) throw new Error('图片编辑使用 --image 指定局部画布;额外参考图也通过重复 --image 指定');
console.log(`图片编辑接入测试:${stage.model}`);