@petercjl/cloud-hug-style-transfer 0.2.0 → 0.3.0
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/README.md +1 -1
- package/capabilities.json +14 -2
- package/npm/canvas-layout.mjs +30 -0
- package/npm/cli.mjs +6 -1
- package/npm/integrity.json +6 -5
- package/npm/media-dependency.mjs +2 -0
- package/package.json +1 -1
- package/skills/cloud-hug-style-transfer/SKILL.md +6 -2
- package/skills/cloud-hug-style-transfer/adapters/codex.json +23 -0
- package/skills/cloud-hug-style-transfer/adapters/sealseek.json +23 -0
- package/skills/cloud-hug-style-transfer/adapters/workbuddy.json +23 -0
- package/skills/cloud-hug-style-transfer/capabilities.json +44 -0
- package/skills/cloud-hug-style-transfer/references/canvas-comparison.md +50 -0
package/README.md
CHANGED
package/capabilities.json
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"skill install",
|
|
17
17
|
"skill update",
|
|
18
18
|
"update check",
|
|
19
|
-
"update install"
|
|
19
|
+
"update install",
|
|
20
|
+
"canvas row"
|
|
20
21
|
],
|
|
21
22
|
"requirements": {
|
|
22
23
|
"node": ">=22",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"missing": "pause",
|
|
38
39
|
"skill": "sealseek-media",
|
|
39
40
|
"source": "CLI skill source --json",
|
|
40
|
-
"contract": "media.generate with image/reference-image/dry-run/task-record/local-artifact"
|
|
41
|
+
"contract": "media.generate with image/reference-image/dry-run/task-record/local-artifact; canvas_contract@1 create/image upload/media inspect/explicit batch/verified readback"
|
|
41
42
|
}
|
|
42
43
|
]
|
|
43
44
|
},
|
|
@@ -58,5 +59,16 @@
|
|
|
58
59
|
"installation": "implemented",
|
|
59
60
|
"generation": "implemented-not-runtime-tested"
|
|
60
61
|
}
|
|
62
|
+
},
|
|
63
|
+
"canvas": {
|
|
64
|
+
"creation": "new-per-generation-request-before-first-submit",
|
|
65
|
+
"title": "application-inferred-from-current-images-and-intent",
|
|
66
|
+
"layout": "source-left-result-right; rows-top-to-bottom",
|
|
67
|
+
"column_width": 480,
|
|
68
|
+
"horizontal_gap": 24,
|
|
69
|
+
"vertical_gap": 32,
|
|
70
|
+
"archive": "none during generation; explicit pair batch after each success",
|
|
71
|
+
"planner": "canvas row --input JSON_FILE --json",
|
|
72
|
+
"recovery": "same canvas/task/row IDs; inspect before replay"
|
|
61
73
|
}
|
|
62
74
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { fail } from './runtime.mjs';
|
|
2
|
+
|
|
3
|
+
// Application layout only: service calls, uploads and verified writes belong
|
|
4
|
+
// to sealseek-media-cli. The original fits the result's row without cropping.
|
|
5
|
+
export function comparisonRow(input) {
|
|
6
|
+
if(!input || typeof input!=='object' || Array.isArray(input)) throw fail('INVALID_INPUT','Expected a comparison row object.');
|
|
7
|
+
const {run_id,row_index,top=0,source,result}=input;
|
|
8
|
+
if(typeof run_id!=='string'||!/^[a-zA-Z0-9_-]{1,80}$/.test(run_id)) throw fail('INVALID_INPUT','run_id must be a stable 1-80 character ASCII operation key.');
|
|
9
|
+
if(!Number.isSafeInteger(row_index)||row_index<1||row_index>10000||!Number.isFinite(top)||top<0||top>1e9) throw fail('INVALID_INPUT','Invalid row index or top coordinate.');
|
|
10
|
+
for(const asset of [source,result]) {
|
|
11
|
+
if(!asset||![asset.width,asset.height].every(v=>Number.isSafeInteger(v)&&v>0)) throw fail('INVALID_INPUT','Both assets need measured positive integer dimensions.');
|
|
12
|
+
let url;try{url=new URL(asset.url);}catch{throw fail('INVALID_INPUT','Both assets need uploaded HTTP(S) URLs.');}
|
|
13
|
+
if(!['https:','http:'].includes(url.protocol)||url.username||url.password) throw fail('INVALID_INPUT','Asset URLs must use HTTP(S) without embedded credentials.');
|
|
14
|
+
}
|
|
15
|
+
const width=480,horizontalGap=24,verticalGap=32;
|
|
16
|
+
const height=width*result.height/result.width;
|
|
17
|
+
const scale=Math.min(width/source.width,height/source.height);
|
|
18
|
+
const sourceWidth=source.width*scale,sourceHeight=source.height*scale;
|
|
19
|
+
if(![height,sourceWidth,sourceHeight].every(n=>Number.isFinite(n)&&n>0&&n<=100000)||top+height+verticalGap>1e9) throw fail('LAYOUT_UNSUPPORTED','Image geometry exceeds the canvas contract.');
|
|
20
|
+
const rects=[{x:(width-sourceWidth)/2,y:top,width:sourceWidth,height:sourceHeight},{x:width+horizontalGap,y:top,width,height}];
|
|
21
|
+
const media=[source,result].map((asset,index)=>({
|
|
22
|
+
id:`${run_id}-row-${row_index}-${index===0?'source':'result'}`,kind:'image',urls:[asset.url],
|
|
23
|
+
placement:{mode:'explicit',positions:[rects[index]]}
|
|
24
|
+
}));
|
|
25
|
+
if(result.generationParams!==undefined) {
|
|
26
|
+
if(!result.generationParams||typeof result.generationParams!=='object'||Array.isArray(result.generationParams)) throw fail('INVALID_INPUT','generationParams must be an object accepted by the media CLI.');
|
|
27
|
+
media[1].generationParams=result.generationParams;
|
|
28
|
+
}
|
|
29
|
+
return {ok:true,row_index,top,next_top:top+height+verticalGap,layout:{column_width:width,horizontal_gap:horizontalGap,vertical_gap:verticalGap},batch:{frames:[],media}};
|
|
30
|
+
}
|
package/npm/cli.mjs
CHANGED
|
@@ -5,12 +5,17 @@ import { root, pkg, fail } from './runtime.mjs';
|
|
|
5
5
|
import { source, targetPath, status, install, inventory } from './skills.mjs';
|
|
6
6
|
import { checkUpdate, installUpdate } from './update.mjs';
|
|
7
7
|
import { mediaDependency } from './media-dependency.mjs';
|
|
8
|
+
import { comparisonRow } from './canvas-layout.mjs';
|
|
8
9
|
const args=process.argv.slice(2);
|
|
9
10
|
const option=name=>{const i=args.indexOf(name);if(i<0)return undefined;if(!args[i+1]||args[i+1].startsWith('--'))throw fail('INVALID_ARGUMENT',`${name} needs a value.`);return args[i+1];};
|
|
10
11
|
const out=value=>console.log(JSON.stringify(value,null,2));
|
|
11
12
|
try {
|
|
12
13
|
if(args[0]==='version'||args[0]==='--version') out({ok:true,name:pkg.name,version:pkg.version});
|
|
13
14
|
else if(args[0]==='capabilities') out({...JSON.parse(fs.readFileSync(path.join(root,'capabilities.json'),'utf8')),version:pkg.version});
|
|
15
|
+
else if(args[0]==='canvas'&&args[1]==='row') {
|
|
16
|
+
const input=option('--input');if(!input)throw fail('INVALID_ARGUMENT','canvas row requires --input JSON_FILE.');
|
|
17
|
+
out(comparisonRow(JSON.parse(fs.readFileSync(input,'utf8'))));
|
|
18
|
+
}
|
|
14
19
|
else if(args[0]==='skill') {
|
|
15
20
|
const action=args[1];
|
|
16
21
|
if(action==='source')out({ok:true,package:pkg.name,version:pkg.version,source});
|
|
@@ -35,6 +40,6 @@ try {
|
|
|
35
40
|
const check=await checkUpdate();
|
|
36
41
|
if(args[1]==='check'){out(check);if(!check.ok)process.exitCode=1;}
|
|
37
42
|
else {if(!check.ok)throw fail(check.code,'Registry unavailable; installed version retained.');out(check.updateAvailable?installUpdate(check):{ok:true,changed:false,version:pkg.version});}
|
|
38
|
-
} else if(!args.length||['--help','help','-h'].includes(args[0])) console.log('cloud-hug-style-transfer\nversion | capabilities --json | doctor --json [--agent AGENT]\nskill source/status/install/update [--agent codex|sealseek|workbuddy] [--root SKILLS_DIRECTORY]\nupdate check | update install --yes\nNode.js 22+. Updates are explicit; business calls never auto-update.');
|
|
43
|
+
} else if(!args.length||['--help','help','-h'].includes(args[0])) console.log('cloud-hug-style-transfer\nversion | capabilities --json | doctor --json [--agent AGENT]\ncanvas row --input JSON_FILE --json (read-only comparison layout)\nskill source/status/install/update [--agent codex|sealseek|workbuddy] [--root SKILLS_DIRECTORY]\nupdate check | update install --yes\nNode.js 22+. Updates are explicit; business calls never auto-update.');
|
|
39
44
|
else throw fail('INVALID_COMMAND','Unknown command; use --help.');
|
|
40
45
|
} catch(e){out({ok:false,code:e.code||'COMMAND_FAILED',message:e.message});process.exitCode=1;}
|
package/npm/integrity.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"SKILL.md": "
|
|
3
|
-
"adapters/codex.json": "
|
|
4
|
-
"adapters/sealseek.json": "
|
|
5
|
-
"adapters/workbuddy.json": "
|
|
2
|
+
"SKILL.md": "7d7e8c42e4ace458fc92ba9aa544fd9688047136ae991ef10bd1633264a7cdda",
|
|
3
|
+
"adapters/codex.json": "bea8d59e6e0dafae7439693b33356825023516a6f52be02a64c976d7ce47ce76",
|
|
4
|
+
"adapters/sealseek.json": "04ef053762fd4cfc2309573ec87425afad14b2df85a1ea8ef0aa06d98fee1aee",
|
|
5
|
+
"adapters/workbuddy.json": "cd0a1d8d5b9fcebc5a709b8c7523911f41973adb95f71af2c0f644473a43a6b4",
|
|
6
6
|
"agents/openai.yaml": "8afeabba706e83f2f20d616579e8d79b6509fe93427acdc2b650ef6387049983",
|
|
7
7
|
"assets/approved/all-colors-user-finish.webp": "539c77de8ec0dd46a29793befecf813e97ce6ae66f7cbe69486846383b2ae936",
|
|
8
8
|
"assets/approved/brand-kv-user-finish-20261012.png": "cb09198481e779444696864b265c689f467207bf7de9610f7adc2b850f0be7b4",
|
|
@@ -55,9 +55,10 @@
|
|
|
55
55
|
"assets/rejected/brand-kv-c2-20261012.webp": "88ed2de0d950ea4a34519661481877ee0899743a6dfce203a2033c0dab6a73f7",
|
|
56
56
|
"assets/rejected/overhead-rest-b.webp": "16e5e6fabdc665868ac244d556f3a8a93db826a34425fdee042e4f7a8ebf64c3",
|
|
57
57
|
"assets/rejected/prone-pile-a.webp": "d07f38bbb69fc23b30dca4ed27faa3d7ae58e2e81840a1c3d46101911c28a7a2",
|
|
58
|
-
"capabilities.json": "
|
|
58
|
+
"capabilities.json": "5d40595bf64402acf700cbaea63065d104547b12e59c275bca59cc9b4658de85",
|
|
59
59
|
"references/assets.md": "5675ee6b395caca641e8ce56e200cd4391ad67e7afceb44fc6732f253a126926",
|
|
60
60
|
"references/brand-layout.md": "5668190c1e618a903aa1b5e859405fa43a004da2082dc7040e83ef8cfc0aae86",
|
|
61
|
+
"references/canvas-comparison.md": "df85594c92de3e87daa85ee7cd9cc92df4be9049a5d42c32904542faf329a6c7",
|
|
61
62
|
"references/cases.md": "9d0d2d3d210e367411d5a291fc78ef6c9c733afd79c9da76451c580fcbcd4d3e",
|
|
62
63
|
"references/detail-final-20261016.md": "14acdc2f991b9db1c7d9ada32a35782603ac0aa310dcbe75f9693796a06cad83",
|
|
63
64
|
"references/kv-layout-case-20261012.md": "845b287cfc57912aabedc48e558ca661cf86bf136304ea841030205a806ef06f",
|
package/npm/media-dependency.mjs
CHANGED
|
@@ -40,6 +40,8 @@ export function mediaDependency({ env = process.env, packageRoot } = {}) {
|
|
|
40
40
|
const contract=JSON.parse(fs.readFileSync(path.join(source,'capabilities.json'),'utf8'));
|
|
41
41
|
const generate=contract.capabilities?.find(c=>c.id==='media.generate');
|
|
42
42
|
if(!['image','reference-image','dry-run','task-record','local-artifact'].every(f=>generate?.required_features?.includes(f))) return missing('DEPENDENCY_INCOMPATIBLE','Media generation contract is incomplete.');
|
|
43
|
+
const canvas=contract.canvas_contract;
|
|
44
|
+
if(canvas?.version!==1||!['explicit-placement','frame-batch','media-inspect'].every(f=>canvas.features?.includes(f))||!canvas.operations?.create||!canvas.operations?.upload?.some(c=>c.startsWith('image upload '))||!canvas.generation_options?.archive?.enum?.includes('none')) return missing('DEPENDENCY_INCOMPATIBLE','Media canvas creation, upload, inspection and explicit batch placement are required.');
|
|
43
45
|
return {ok:true,package:name,version:pkg.version,entry,source,invocation:{command:process.execPath,args:[entry]},serviceAccess:'requires-live-preflight',generationTested:false};
|
|
44
46
|
} catch { return missing('DEPENDENCY_INVALID','Media package, CLI or canonical Skill could not be verified.'); }
|
|
45
47
|
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ description: 独立把旧详情页、产品摄影、主KV或SKU转换为抱抱
|
|
|
9
9
|
|
|
10
10
|
## 运行合同与平台入口
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
输入是当前源页、商品资料和本次目标;输出是约定数量的独立成图、原图与成图逐行对照的无限画板及简短验收说明,或用户仅要求的规划。本 Skill 负责品牌方法、素材选择、提示词、版式和业务验收;`@petercjl/sealseek-media-cli` 负责生图服务、认证、参考图传输、任务恢复和结果下载;宿主负责命令执行、实际看图和交付。
|
|
13
13
|
|
|
14
14
|
### 入口:必需依赖检查
|
|
15
15
|
|
|
@@ -106,7 +106,9 @@ description: 独立把旧详情页、产品摄影、主KV或SKU转换为抱抱
|
|
|
106
106
|
|
|
107
107
|
查实际说明有无相反要求:无字却夹带标题;安睡却强求笑容露全脸;亲密近景却一律缩小主体;尺寸展示却遮挡关键轮廓;柔软品牌却全套粗圆字。修正具体冲突,不靠末尾追加“自然、高级、有呼吸感”抵消。
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
**生成执行先读取 [无限画板对照归档](references/canvas-comparison.md)。每个新生图任务在首张实际生图前,新建按用户图片与用途自动命名的画板。每张成功后立即插入左原图、右成图的一对独立元素,后续行向下紧凑排列;归档核验通过后再处理下一张。规划任务不创建画板。**
|
|
110
|
+
|
|
111
|
+
调用当前适配中由 `sealseek-media-cli` 实现的 `media.image.edit`。按已加载的 `sealseek-media` 主线读取当前模型能力,用其参考图生成/编辑合同传入真实原图与精简提示词,先 `--dry-run --json`,通过后在已有生成授权范围内用 `--canvas 本轮画板ID --archive none --via sealseek --submit` 提交,成功后按对照归档合同把原图与成图实际成对插入本轮画板。模型采用媒体包当前默认值,用户明确指定时保留指定值;模型不支持本轮要求时暂停并报告,不自动换模型。保存任务 ID,按依赖合同查询、恢复、下载;提交结果不明先核对同一任务,不自动重提或增加付费生成。执行中依赖丢失或服务不可用时暂停,恢复后回到既有任务或本执行节点。保留精简实际调用记录,不向使用者倾倒完整日志。
|
|
110
112
|
|
|
111
113
|
分别要三张就交三张独立成稿,已授权数量连续完成,不自行拼成方案墙。创意备选应有真实观看或图文关系差异;比较型延展可保留同一骨架。一大两小、同构与否取决于页面,而非出图张数。
|
|
112
114
|
|
|
@@ -121,3 +123,5 @@ description: 独立把旧详情页、产品摄影、主KV或SKU转换为抱抱
|
|
|
121
123
|
5. **连续阅读与备选**:比较段的重复是否帮助比较,跨段变化是否推进内容;三案是否真正提供选择。摄影变清晰或产品基本准确,不能替代整体设计成立。
|
|
122
124
|
|
|
123
125
|
整体成立时定向修局部;空间、状态或设计关系失败时调整对应关系,不锁住失败构图只修部件。遵守允许修改范围和数量,不默认额外跑多轮。交付如实说明仍有的关键问题;规则和规划检查不能证明实际生成效果已达标。
|
|
126
|
+
|
|
127
|
+
交付还须按画板归档合同核对名称、真实链接、左右源图关系、逐行顺序与紧凑间距;每张都已实际成对写入并核验,才报告画板归档完成。
|
|
@@ -39,6 +39,29 @@
|
|
|
39
39
|
"evidence": [
|
|
40
40
|
"Canonical sealseek-media 0.6.1 CLI/Skill and live capabilities inspected; paid generation and full host flow not tested."
|
|
41
41
|
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"capability_id": "media.canvas.compare",
|
|
45
|
+
"status": "implemented",
|
|
46
|
+
"features": [
|
|
47
|
+
"new-canvas",
|
|
48
|
+
"source-upload",
|
|
49
|
+
"actual-dimensions",
|
|
50
|
+
"explicit-placement",
|
|
51
|
+
"idempotent-pair-import",
|
|
52
|
+
"verified-save"
|
|
53
|
+
],
|
|
54
|
+
"implementation": {
|
|
55
|
+
"type": "cli",
|
|
56
|
+
"discovery": "Use the verified media invocation from doctor; load canonical sealseek-media Skill and its current canvas creation, upload, inspection and explicit batch contract.",
|
|
57
|
+
"invocation": "Follow references/canvas-comparison.md for application naming, pairing, row state and layout; use media CLI canvas create, image upload, media inspect, canvas batch and canvas get. Pass an explicit canvas ID and archive none during generation; archive each pair after completion.",
|
|
58
|
+
"configuration": "Existing media-package private authentication and network. canvas_contract version 1; no new provider integration.",
|
|
59
|
+
"failure": "Pause on missing canvas contract, failed/uncertain creation, upload or pair write. Preserve IDs and original batch; inspect the same canvas before recovery."
|
|
60
|
+
},
|
|
61
|
+
"normalization": "Success includes canvas_id, canvas_url and verified pair positions; failure retains code, task/canvas IDs and recovery state.",
|
|
62
|
+
"evidence": [
|
|
63
|
+
"Current media CLI contract inspected; deterministic geometry and batch dry-run tested separately from real canvas writes."
|
|
64
|
+
]
|
|
42
65
|
}
|
|
43
66
|
],
|
|
44
67
|
"operating_systems": {
|
|
@@ -41,6 +41,29 @@
|
|
|
41
41
|
"evidence": [
|
|
42
42
|
"Canonical sealseek-media 0.6.1 CLI/Skill and live capabilities inspected; paid generation and full host flow not tested."
|
|
43
43
|
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"capability_id": "media.canvas.compare",
|
|
47
|
+
"status": "implemented",
|
|
48
|
+
"features": [
|
|
49
|
+
"new-canvas",
|
|
50
|
+
"source-upload",
|
|
51
|
+
"actual-dimensions",
|
|
52
|
+
"explicit-placement",
|
|
53
|
+
"idempotent-pair-import",
|
|
54
|
+
"verified-save"
|
|
55
|
+
],
|
|
56
|
+
"implementation": {
|
|
57
|
+
"type": "cli",
|
|
58
|
+
"discovery": "Use the verified media invocation from doctor; load canonical sealseek-media Skill and its current canvas creation, upload, inspection and explicit batch contract.",
|
|
59
|
+
"invocation": "Follow references/canvas-comparison.md for application naming, pairing, row state and layout; use media CLI canvas create, image upload, media inspect, canvas batch and canvas get. Pass an explicit canvas ID and archive none during generation; archive each pair after completion.",
|
|
60
|
+
"configuration": "Existing media-package private authentication and network. canvas_contract version 1; no new provider integration.",
|
|
61
|
+
"failure": "Pause on missing canvas contract, failed/uncertain creation, upload or pair write. Preserve IDs and original batch; inspect the same canvas before recovery."
|
|
62
|
+
},
|
|
63
|
+
"normalization": "Success includes canvas_id, canvas_url and verified pair positions; failure retains code, task/canvas IDs and recovery state.",
|
|
64
|
+
"evidence": [
|
|
65
|
+
"Current media CLI contract inspected; deterministic geometry and batch dry-run tested separately from real canvas writes."
|
|
66
|
+
]
|
|
44
67
|
}
|
|
45
68
|
],
|
|
46
69
|
"operating_systems": {
|
|
@@ -41,6 +41,29 @@
|
|
|
41
41
|
"evidence": [
|
|
42
42
|
"Canonical sealseek-media 0.6.1 CLI/Skill and live capabilities inspected; paid generation and full host flow not tested."
|
|
43
43
|
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"capability_id": "media.canvas.compare",
|
|
47
|
+
"status": "implemented",
|
|
48
|
+
"features": [
|
|
49
|
+
"new-canvas",
|
|
50
|
+
"source-upload",
|
|
51
|
+
"actual-dimensions",
|
|
52
|
+
"explicit-placement",
|
|
53
|
+
"idempotent-pair-import",
|
|
54
|
+
"verified-save"
|
|
55
|
+
],
|
|
56
|
+
"implementation": {
|
|
57
|
+
"type": "cli",
|
|
58
|
+
"discovery": "Use the verified media invocation from doctor; load canonical sealseek-media Skill and its current canvas creation, upload, inspection and explicit batch contract.",
|
|
59
|
+
"invocation": "Follow references/canvas-comparison.md for application naming, pairing, row state and layout; use media CLI canvas create, image upload, media inspect, canvas batch and canvas get. Pass an explicit canvas ID and archive none during generation; archive each pair after completion.",
|
|
60
|
+
"configuration": "Existing media-package private authentication and network. canvas_contract version 1; no new provider integration.",
|
|
61
|
+
"failure": "Pause on missing canvas contract, failed/uncertain creation, upload or pair write. Preserve IDs and original batch; inspect the same canvas before recovery."
|
|
62
|
+
},
|
|
63
|
+
"normalization": "Success includes canvas_id, canvas_url and verified pair positions; failure retains code, task/canvas IDs and recovery state.",
|
|
64
|
+
"evidence": [
|
|
65
|
+
"Current media CLI contract inspected; deterministic geometry and batch dry-run tested separately from real canvas writes."
|
|
66
|
+
]
|
|
44
67
|
}
|
|
45
68
|
],
|
|
46
69
|
"operating_systems": {
|
|
@@ -79,6 +79,50 @@
|
|
|
79
79
|
"DEPENDENCY_INCOMPATIBLE"
|
|
80
80
|
],
|
|
81
81
|
"provider": "@petercjl/sealseek-media-cli"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "media.canvas.compare",
|
|
85
|
+
"purpose": "首张生图前新建命名画板,逐张成对插入左原图右成图并验证紧凑逐行布局",
|
|
86
|
+
"required": true,
|
|
87
|
+
"required_features": [
|
|
88
|
+
"new-canvas",
|
|
89
|
+
"source-upload",
|
|
90
|
+
"actual-dimensions",
|
|
91
|
+
"explicit-placement",
|
|
92
|
+
"idempotent-pair-import",
|
|
93
|
+
"verified-save"
|
|
94
|
+
],
|
|
95
|
+
"input_fields": [
|
|
96
|
+
"title",
|
|
97
|
+
"canvas_id",
|
|
98
|
+
"images",
|
|
99
|
+
"row_layout",
|
|
100
|
+
"authorization"
|
|
101
|
+
],
|
|
102
|
+
"output_fields": [
|
|
103
|
+
"ok",
|
|
104
|
+
"artifacts",
|
|
105
|
+
"metadata",
|
|
106
|
+
"canvas_id",
|
|
107
|
+
"canvas_url",
|
|
108
|
+
"verified",
|
|
109
|
+
"warnings"
|
|
110
|
+
],
|
|
111
|
+
"side_effects": {
|
|
112
|
+
"external_mutation": true,
|
|
113
|
+
"may_cost_money": false,
|
|
114
|
+
"authorization": "Authorized image task includes its new canvas, source uploads and result archival; generation remains separately authorized."
|
|
115
|
+
},
|
|
116
|
+
"errors": [
|
|
117
|
+
"DEPENDENCY_MISSING",
|
|
118
|
+
"DEPENDENCY_INCOMPATIBLE",
|
|
119
|
+
"AUTH_REQUIRED",
|
|
120
|
+
"CAPABILITY_UNAVAILABLE",
|
|
121
|
+
"FEATURE_UNSUPPORTED",
|
|
122
|
+
"SUBMISSION_UNCERTAIN",
|
|
123
|
+
"IDEMPOTENCY_CONFLICT",
|
|
124
|
+
"OUTPUT_CONTRACT_FAILED"
|
|
125
|
+
]
|
|
82
126
|
}
|
|
83
127
|
],
|
|
84
128
|
"dependencies": [
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# 无限画板:逐图左右对照
|
|
2
|
+
|
|
3
|
+
仅进入生成执行节点时读取。输入是本轮商品/用途、源图与生成计划;输出是一个新建且贴切命名的无限画板文件,每张成图一行,原图在左、成图在右,后续行紧凑向下排列。这里决定命名、图片职责、布局和进度;服务操作由当前 `sealseek-media` Skill 承接。
|
|
4
|
+
|
|
5
|
+
## 1. 准备本轮画板
|
|
6
|
+
|
|
7
|
+
先通过入口依赖、登录和模型能力检查,完成本轮生成参数 dry-run,再创建画板。用户只要求看图或规划时不创建;明确开始生成或批准生成后,每个新的生图任务新建一个画板,同一任务的多张图片共用它。恢复中断、查询旧任务及继续本轮时沿用已记录的画板,不重复创建。
|
|
8
|
+
|
|
9
|
+
实际看用户图片,按“商品或视觉主题+本次用途/特点”取一个好记的简短中文名称,例如“蓝兔抱枕·柔光详情页”“云朵沙发·主图焕新”。使用能确认的内容,资料不足时用任务用途命名,不编造品牌或型号。用户指定标题时使用指定值;同名任务可加短日期或简短序号区分,不用原始文件乱码或长任务 ID 作标题。
|
|
10
|
+
|
|
11
|
+
通过已核验的媒体 CLI 读取当前 `references/cli.md` 中 Canvas operations and placement、Native Frames, explicit batches and existing-media metadata 合同。调用 `canvas create --title 名称 --submit --json`,保存真实 `canvas_id`、名称和链接,使用 `canvas get ID --json` 核对后才开始实际生图。画板创建失败或结果不明时暂停;检查已有记录及 `canvas list`,确认同一次创建的结果,不盲目再建一个。
|
|
12
|
+
|
|
13
|
+
在当前任务的本地项目目录保存进度:稳定的 `run_id`、画板 ID/名称/链接、源图路径及对应关系、有序行清单、任务 ID、上传 URL、实际尺寸、批次 JSON、每行写入状态和下一行 top。敏感参数与私人路径仅留本地;写前检查路径,已有进度读取恢复,已有用户文件保留。新任务用独立目录和新的 run_id。
|
|
14
|
+
|
|
15
|
+
## 2. 每生成一张,插入一对图片
|
|
16
|
+
|
|
17
|
+
按用户约定顺序逐张执行,每个任务请求一张图片。生成命令明确传入本轮 `--canvas ID --archive none`,先 dry-run,通过后按已授权范围提交。`none` 用于在结果实际尺寸确定后成对归档,服务生成历史仍属于该画板;后续步骤会实际插入成图。每张保存并跟踪其任务 ID,成功后获取可用 URL、本地文件及实际尺寸。
|
|
18
|
+
|
|
19
|
+
左侧原图是这一张成图对应的用户待转换源图,不是内置品牌案例或人物卡。同一原图生成多张方案时,每一行各插入该原图与对应成图。多张源图按既定配对关系逐行处理;确需多张源图共同生成且无法确定主要对照图时,先明确主要源图。
|
|
20
|
+
|
|
21
|
+
使用媒体 CLI 的 `image upload FILE --submit --json` 上传左侧原图,并通过其当前的实际尺寸检查合同取得原图及成图宽高。已成功上传且文件哈希未变的同一原图复用 URL,画板上仍按每行分别显示。成图使用同一任务已返回的 URL,不为排版重新生成或重新压缩图片。
|
|
22
|
+
|
|
23
|
+
每完成一张立即计算这一行并成对插入,再处理下一张:
|
|
24
|
+
|
|
25
|
+
- 左、右各预留宽 480 个画板单位,列间距 24;右图显示宽 480,高度按其实际比例计算。
|
|
26
|
+
- 原图等比完整放入左侧的 480 × 右图显示高度范围,顶部对齐并在左列水平居中。由画板显示缩放保持原图完整与成图紧邻,不拉伸、裁切或拼成一张图。
|
|
27
|
+
- 第一行 top 为 0;下一行 top = 本行 top + 右图显示高度 + 32。这样每张成图紧接上一张成图下方,原图也不会侵入下一行。
|
|
28
|
+
- 左右两图始终是两个独立图片元素,保持原始 URL 和分辨率。生成详情以媒体包支持的隐藏 generationParams 保存,不往图片里添加文字。
|
|
29
|
+
|
|
30
|
+
使用本应用 CLI 的确定性布局命令 `cloud-hug-style-transfer canvas row --input ROW.json --json`,套件安装可经其 `component run cloud-hug-style-transfer` 入口调用。它只读输入并返回布局,不创建画板、不上传或生图。输入示例:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"run_id": "stable-run-key",
|
|
35
|
+
"row_index": 1,
|
|
36
|
+
"top": 0,
|
|
37
|
+
"source": {"url": "https://example.com/source.png", "width": 1200, "height": 1800},
|
|
38
|
+
"result": {"url": "https://example.com/result.png", "width": 1200, "height": 1800}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
实际输入使用上传和任务返回的真实 URL 及实测尺寸。成图可提供 `generationParams`,仅选用媒体包当前支持的提示词、模型、画幅、参数及参考 URL 等生成详情字段,不复制凭据、请求头、私人路径或完整任务内部记录。
|
|
43
|
+
|
|
44
|
+
把返回的 `batch` 单独保存成批次 JSON,先执行媒体 CLI `canvas batch ID --file BATCH.json --json` 验证,再加 `--submit` 写入。稳定元素 ID 包含 run_id、row_index 及 source/result,重复执行同一批次具有幂等性。要求写入结果 verified,并回读同一画板核对这一对的 URL、位置、比例和两图数量;确认后才记录 next_top 并进入下一行。
|
|
45
|
+
|
|
46
|
+
## 3. 恢复与验收
|
|
47
|
+
|
|
48
|
+
单张失败保留前面已完成的对照行及当前任务 ID;后续恢复从该行继续,顺序不变。归档失败或写入结果不明时,保存结果文件和原批次,先 `canvas get` 核对稳定元素 ID,再依据媒体包恢复合同修复同一批次;不要以新元素 ID 绕过冲突,不用默认网格重排,也不通过 `task sync` 的默认追加另插一份成图。已有人为移动、删除或并发改动时暂停并报告差异,不自动恢复被删元素或移动旧行。
|
|
49
|
+
|
|
50
|
+
完成标准:画板名称与当前主题/用途匹配,全部约定成图按顺序形成左右对照,每行左原图、右成图,成图上下间距 32、左右列间距 24,比例正确、无重叠和重复项,实际写入已核验。交付独立图片与验收说明时同时给出画板名称和真实链接;未成功成对归档时明确报告未完成部分。
|