mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-18 15:50:25 +02:00
* feat: bundle standalone taste distillation and application workflows * docs: fix imported taste skill markdown lint * docs: align Turkish agent catalog with taste skills * refactor: make ECC the canonical reusable video engine * fix: preserve video duration when applying image overlays * fix: preserve background colors in image compositing * fix: report best-effort duration targets and shortfalls * feat: ship verified Fusion presets with compatibility provenance * feat(tasteforge): preserve native edits in application bundles * feat(tasteforge): compile local preservation without hosted input * fix: update js-yaml to patched 4.3.2 * test: report bounded Stop wrapper failure diagnostics * fix(tasteforge): fail closed on unsafe output names, missing overlays and cadence - cli: default report and spec paths are derived from pack name and profile genre; require the manifest's name pattern before using either as a filename part so a traversal string cannot write outside cwd/out. - apply_local: a pack without cadence.json, or with no measured shots and no explicit mean_shot, raises instead of silently planning 1.0s shots and reporting a measured cadence. - legacy apply: a missing overlay aborts before any paid upload; forge() would have rejected it after every take was generated. - requirements-live: pin fal-client>=0.13.0, the first release whose subscribe() accepts client_timeout. Addresses the five P1 findings from the independent review of #3033. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fxHRsydPqEcYngGbqkgt1 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
227 lines
5.1 KiB
JSON
227 lines
5.1 KiB
JSON
{
|
|
"name": "taste-apply-30fps",
|
|
"title": "taste-apply-30fps",
|
|
"contents": {
|
|
"name": "workflow",
|
|
"nodes": {
|
|
"node-xfirst": {
|
|
"type": "run",
|
|
"id": "node-xfirst",
|
|
"depends": [
|
|
"input"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 340,
|
|
"y": -320
|
|
}
|
|
},
|
|
"app": "fal-ai/ffmpeg-api/extract-frame",
|
|
"input": {
|
|
"video_url": "$input.source_video",
|
|
"frame_type": "first"
|
|
}
|
|
},
|
|
"node-gen1": {
|
|
"type": "run",
|
|
"id": "node-gen1",
|
|
"depends": [
|
|
"input",
|
|
"node-xfirst"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 760,
|
|
"y": -320
|
|
}
|
|
},
|
|
"app": "bytedance/seedance-2.5/reference-to-video",
|
|
"input": {
|
|
"prompt": "$input.compiled_prompt",
|
|
"image_urls": [
|
|
"$node-xfirst.images.0.url"
|
|
],
|
|
"duration": "5",
|
|
"resolution": "720p",
|
|
"audio_urls": [],
|
|
"generate_audio": false
|
|
}
|
|
},
|
|
"node-xmid": {
|
|
"type": "run",
|
|
"id": "node-xmid",
|
|
"depends": [
|
|
"input"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 340,
|
|
"y": 0
|
|
}
|
|
},
|
|
"app": "fal-ai/ffmpeg-api/extract-frame",
|
|
"input": {
|
|
"video_url": "$input.source_video",
|
|
"frame_type": "middle"
|
|
}
|
|
},
|
|
"node-gen2": {
|
|
"type": "run",
|
|
"id": "node-gen2",
|
|
"depends": [
|
|
"input",
|
|
"node-xmid"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 760,
|
|
"y": 0
|
|
}
|
|
},
|
|
"app": "bytedance/seedance-2.5/reference-to-video",
|
|
"input": {
|
|
"prompt": "$input.compiled_prompt",
|
|
"image_urls": [
|
|
"$node-xmid.images.0.url"
|
|
],
|
|
"duration": "5",
|
|
"resolution": "720p",
|
|
"audio_urls": [],
|
|
"generate_audio": false
|
|
}
|
|
},
|
|
"node-xlast": {
|
|
"type": "run",
|
|
"id": "node-xlast",
|
|
"depends": [
|
|
"input"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 340,
|
|
"y": 320
|
|
}
|
|
},
|
|
"app": "fal-ai/ffmpeg-api/extract-frame",
|
|
"input": {
|
|
"video_url": "$input.source_video",
|
|
"frame_type": "last"
|
|
}
|
|
},
|
|
"node-gen3": {
|
|
"type": "run",
|
|
"id": "node-gen3",
|
|
"depends": [
|
|
"input",
|
|
"node-xlast"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 760,
|
|
"y": 320
|
|
}
|
|
},
|
|
"app": "bytedance/seedance-2.5/reference-to-video",
|
|
"input": {
|
|
"prompt": "$input.compiled_prompt",
|
|
"image_urls": [
|
|
"$node-xlast.images.0.url"
|
|
],
|
|
"duration": "5",
|
|
"resolution": "720p",
|
|
"audio_urls": [],
|
|
"generate_audio": false
|
|
}
|
|
},
|
|
"node-merge": {
|
|
"type": "run",
|
|
"id": "node-merge",
|
|
"depends": [
|
|
"node-gen1",
|
|
"node-gen2",
|
|
"node-gen3"
|
|
],
|
|
"metadata": {
|
|
"position": {
|
|
"x": 1180,
|
|
"y": 0
|
|
}
|
|
},
|
|
"app": "fal-ai/ffmpeg-api/merge-videos",
|
|
"input": {
|
|
"video_urls": [
|
|
"$node-gen1.video.url",
|
|
"$node-gen2.video.url",
|
|
"$node-gen3.video.url"
|
|
],
|
|
"target_fps": 30
|
|
}
|
|
},
|
|
"output": {
|
|
"type": "display",
|
|
"id": "output",
|
|
"depends": [
|
|
"node-merge"
|
|
],
|
|
"input": {},
|
|
"metadata": {
|
|
"position": {
|
|
"x": 1600,
|
|
"y": 0
|
|
}
|
|
},
|
|
"fields": {
|
|
"reel": "$node-merge.video",
|
|
"take_1": "$node-gen1.video",
|
|
"take_2": "$node-gen2.video",
|
|
"take_3": "$node-gen3.video"
|
|
}
|
|
}
|
|
},
|
|
"output": {
|
|
"reel": "$node-merge.video",
|
|
"take_1": "$node-gen1.video",
|
|
"take_2": "$node-gen2.video",
|
|
"take_3": "$node-gen3.video"
|
|
},
|
|
"schema": {
|
|
"input": {
|
|
"source_video": {
|
|
"name": "video_url",
|
|
"label": "Own-content source video",
|
|
"description": "Content reference; taste structure comes from compiled_prompt.",
|
|
"required": true,
|
|
"defaultValue": "",
|
|
"examples": [],
|
|
"ui": {},
|
|
"type": "string",
|
|
"modelId": "node-xfirst"
|
|
},
|
|
"compiled_prompt": {
|
|
"name": "text",
|
|
"label": "Compiled WHAT / HOW / GRADE prompt",
|
|
"description": "Compile offline with workflow_graphs.py.",
|
|
"required": true,
|
|
"defaultValue": "",
|
|
"examples": [],
|
|
"ui": {
|
|
"field": "textarea"
|
|
},
|
|
"type": "string",
|
|
"modelId": "node-gen1"
|
|
}
|
|
},
|
|
"output": {}
|
|
},
|
|
"version": "1",
|
|
"metadata": {
|
|
"input": {
|
|
"position": {
|
|
"x": 0,
|
|
"y": 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|