@kenkaiiii/gg-editor 0.6.7 → 0.7.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/dist/cli.js +64 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/audio-mix.d.ts.map +1 -1
- package/dist/core/audio-mix.js +8 -1
- package/dist/core/audio-mix.js.map +1 -1
- package/dist/core/audio-mix.test.js +1 -1
- package/dist/core/audio-mix.test.js.map +1 -1
- package/dist/core/auth/api-keys.d.ts +1 -1
- package/dist/core/auth/api-keys.d.ts.map +1 -1
- package/dist/core/auth/api-keys.js +2 -1
- package/dist/core/auth/api-keys.js.map +1 -1
- package/dist/core/auth/index.d.ts +18 -5
- package/dist/core/auth/index.d.ts.map +1 -1
- package/dist/core/auth/index.js +16 -4
- package/dist/core/auth/index.js.map +1 -1
- package/dist/core/auth/login.d.ts.map +1 -1
- package/dist/core/auth/login.js +4 -31
- package/dist/core/auth/login.js.map +1 -1
- package/dist/core/beats.d.ts +59 -0
- package/dist/core/beats.d.ts.map +1 -0
- package/dist/core/beats.js +122 -0
- package/dist/core/beats.js.map +1 -0
- package/dist/core/beats.test.d.ts +2 -0
- package/dist/core/beats.test.d.ts.map +1 -0
- package/dist/core/beats.test.js +86 -0
- package/dist/core/beats.test.js.map +1 -0
- package/dist/core/brand-kit.d.ts +80 -0
- package/dist/core/brand-kit.d.ts.map +1 -0
- package/dist/core/brand-kit.js +96 -0
- package/dist/core/brand-kit.js.map +1 -0
- package/dist/core/brand-kit.test.d.ts +2 -0
- package/dist/core/brand-kit.test.d.ts.map +1 -0
- package/dist/core/brand-kit.test.js +76 -0
- package/dist/core/brand-kit.test.js.map +1 -0
- package/dist/core/bundled-sfx.d.ts +64 -0
- package/dist/core/bundled-sfx.d.ts.map +1 -0
- package/dist/core/bundled-sfx.js +218 -0
- package/dist/core/bundled-sfx.js.map +1 -0
- package/dist/core/bundled-sfx.test.d.ts +2 -0
- package/dist/core/bundled-sfx.test.d.ts.map +1 -0
- package/dist/core/bundled-sfx.test.js +81 -0
- package/dist/core/bundled-sfx.test.js.map +1 -0
- package/dist/core/child-abort.d.ts +57 -0
- package/dist/core/child-abort.d.ts.map +1 -0
- package/dist/core/child-abort.js +95 -0
- package/dist/core/child-abort.js.map +1 -0
- package/dist/core/child-abort.test.d.ts +2 -0
- package/dist/core/child-abort.test.d.ts.map +1 -0
- package/dist/core/child-abort.test.js +88 -0
- package/dist/core/child-abort.test.js.map +1 -0
- package/dist/core/clip-scoring.d.ts +44 -0
- package/dist/core/clip-scoring.d.ts.map +1 -0
- package/dist/core/clip-scoring.js +165 -0
- package/dist/core/clip-scoring.js.map +1 -0
- package/dist/core/clip-scoring.test.d.ts +2 -0
- package/dist/core/clip-scoring.test.d.ts.map +1 -0
- package/dist/core/clip-scoring.test.js +113 -0
- package/dist/core/clip-scoring.test.js.map +1 -0
- package/dist/core/emoji-captions.d.ts +45 -0
- package/dist/core/emoji-captions.d.ts.map +1 -0
- package/dist/core/emoji-captions.js +121 -0
- package/dist/core/emoji-captions.js.map +1 -0
- package/dist/core/face-reframe.d.ts +91 -0
- package/dist/core/face-reframe.d.ts.map +1 -0
- package/dist/core/face-reframe.js +141 -0
- package/dist/core/face-reframe.js.map +1 -0
- package/dist/core/face-reframe.test.d.ts +2 -0
- package/dist/core/face-reframe.test.d.ts.map +1 -0
- package/dist/core/face-reframe.test.js +171 -0
- package/dist/core/face-reframe.test.js.map +1 -0
- package/dist/core/filler-words.d.ts +57 -9
- package/dist/core/filler-words.d.ts.map +1 -1
- package/dist/core/filler-words.js +61 -9
- package/dist/core/filler-words.js.map +1 -1
- package/dist/core/filler-words.test.js +91 -17
- package/dist/core/filler-words.test.js.map +1 -1
- package/dist/core/hook-rewrite.d.ts +48 -0
- package/dist/core/hook-rewrite.d.ts.map +1 -0
- package/dist/core/hook-rewrite.js +151 -0
- package/dist/core/hook-rewrite.js.map +1 -0
- package/dist/core/hook-rewrite.test.d.ts +2 -0
- package/dist/core/hook-rewrite.test.d.ts.map +1 -0
- package/dist/core/hook-rewrite.test.js +58 -0
- package/dist/core/hook-rewrite.test.js.map +1 -0
- package/dist/core/hosts/lazy.d.ts.map +1 -1
- package/dist/core/hosts/lazy.js +2 -0
- package/dist/core/hosts/lazy.js.map +1 -1
- package/dist/core/hosts/premiere/adapter.d.ts +1 -0
- package/dist/core/hosts/premiere/adapter.d.ts.map +1 -1
- package/dist/core/hosts/premiere/adapter.js.map +1 -1
- package/dist/core/hosts/premiere/bridge-source.d.ts.map +1 -1
- package/dist/core/hosts/premiere/bridge-source.js +6 -3
- package/dist/core/hosts/premiere/bridge-source.js.map +1 -1
- package/dist/core/hosts/resolve/adapter.d.ts +1 -0
- package/dist/core/hosts/resolve/adapter.d.ts.map +1 -1
- package/dist/core/hosts/resolve/adapter.js.map +1 -1
- package/dist/core/hosts/resolve/bridge-source.d.ts.map +1 -1
- package/dist/core/hosts/resolve/bridge-source.js +31 -4
- package/dist/core/hosts/resolve/bridge-source.js.map +1 -1
- package/dist/core/hosts/resolve/bridge.d.ts +2 -19
- package/dist/core/hosts/resolve/bridge.d.ts.map +1 -1
- package/dist/core/hosts/resolve/bridge.js +70 -41
- package/dist/core/hosts/resolve/bridge.js.map +1 -1
- package/dist/core/hosts/resolve/bridge.test.js +130 -0
- package/dist/core/hosts/resolve/bridge.test.js.map +1 -1
- package/dist/core/hosts/types.d.ts +6 -0
- package/dist/core/hosts/types.d.ts.map +1 -1
- package/dist/core/hosts/types.js.map +1 -1
- package/dist/core/logger.d.ts +32 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +188 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/loop-match.d.ts +57 -0
- package/dist/core/loop-match.d.ts.map +1 -0
- package/dist/core/loop-match.js +91 -0
- package/dist/core/loop-match.js.map +1 -0
- package/dist/core/media/ffmpeg.d.ts.map +1 -1
- package/dist/core/media/ffmpeg.js +14 -3
- package/dist/core/media/ffmpeg.js.map +1 -1
- package/dist/core/multi-format.d.ts +67 -0
- package/dist/core/multi-format.d.ts.map +1 -0
- package/dist/core/multi-format.js +127 -0
- package/dist/core/multi-format.js.map +1 -0
- package/dist/core/multi-format.test.d.ts +2 -0
- package/dist/core/multi-format.test.d.ts.map +1 -0
- package/dist/core/multi-format.test.js +151 -0
- package/dist/core/multi-format.test.js.map +1 -0
- package/dist/core/python/beats.py +61 -0
- package/dist/core/python/face_reframe.py +163 -0
- package/dist/core/python/sidecar-path.d.ts +13 -0
- package/dist/core/python/sidecar-path.d.ts.map +1 -0
- package/dist/core/python/sidecar-path.js +24 -0
- package/dist/core/python/sidecar-path.js.map +1 -0
- package/dist/core/python.d.ts +57 -0
- package/dist/core/python.d.ts.map +1 -0
- package/dist/core/python.js +107 -0
- package/dist/core/python.js.map +1 -0
- package/dist/core/python.test.d.ts +2 -0
- package/dist/core/python.test.d.ts.map +1 -0
- package/dist/core/python.test.js +129 -0
- package/dist/core/python.test.js.map +1 -0
- package/dist/core/retention-structure.d.ts +81 -0
- package/dist/core/retention-structure.d.ts.map +1 -0
- package/dist/core/retention-structure.js +206 -0
- package/dist/core/retention-structure.js.map +1 -0
- package/dist/core/retention-structure.test.d.ts +2 -0
- package/dist/core/retention-structure.test.d.ts.map +1 -0
- package/dist/core/retention-structure.test.js +88 -0
- package/dist/core/retention-structure.test.js.map +1 -0
- package/dist/core/review.d.ts +17 -0
- package/dist/core/review.d.ts.map +1 -1
- package/dist/core/review.js +20 -24
- package/dist/core/review.js.map +1 -1
- package/dist/core/safe-paths.d.ts +11 -0
- package/dist/core/safe-paths.d.ts.map +1 -1
- package/dist/core/safe-paths.js +26 -10
- package/dist/core/safe-paths.js.map +1 -1
- package/dist/core/safe-paths.test.js +16 -0
- package/dist/core/safe-paths.test.js.map +1 -1
- package/dist/core/skills-loader.d.ts +48 -2
- package/dist/core/skills-loader.d.ts.map +1 -1
- package/dist/core/skills-loader.js +97 -19
- package/dist/core/skills-loader.js.map +1 -1
- package/dist/core/skills-loader.test.js +63 -1
- package/dist/core/skills-loader.test.js.map +1 -1
- package/dist/core/srt.d.ts +42 -7
- package/dist/core/srt.d.ts.map +1 -1
- package/dist/core/srt.js +101 -32
- package/dist/core/srt.js.map +1 -1
- package/dist/core/srt.test.js +54 -1
- package/dist/core/srt.test.js.map +1 -1
- package/dist/core/thumbnail-compose.d.ts +58 -0
- package/dist/core/thumbnail-compose.d.ts.map +1 -0
- package/dist/core/thumbnail-compose.js +101 -0
- package/dist/core/thumbnail-compose.js.map +1 -0
- package/dist/core/thumbnail-promise.d.ts +46 -0
- package/dist/core/thumbnail-promise.d.ts.map +1 -0
- package/dist/core/thumbnail-promise.js +133 -0
- package/dist/core/thumbnail-promise.js.map +1 -0
- package/dist/core/thumbnail-promise.test.d.ts +2 -0
- package/dist/core/thumbnail-promise.test.d.ts.map +1 -0
- package/dist/core/thumbnail-promise.test.js +52 -0
- package/dist/core/thumbnail-promise.test.js.map +1 -0
- package/dist/core/viral-moments.d.ts +70 -0
- package/dist/core/viral-moments.d.ts.map +1 -0
- package/dist/core/viral-moments.js +192 -0
- package/dist/core/viral-moments.js.map +1 -0
- package/dist/core/viral-moments.test.d.ts +2 -0
- package/dist/core/viral-moments.test.d.ts.map +1 -0
- package/dist/core/viral-moments.test.js +153 -0
- package/dist/core/viral-moments.test.js.map +1 -0
- package/dist/core/whisper.d.ts +16 -0
- package/dist/core/whisper.d.ts.map +1 -1
- package/dist/core/whisper.js +72 -5
- package/dist/core/whisper.js.map +1 -1
- package/dist/core/whisper.test.js +111 -1
- package/dist/core/whisper.test.js.map +1 -1
- package/dist/core/youtube-metadata.d.ts +44 -0
- package/dist/core/youtube-metadata.d.ts.map +1 -0
- package/dist/core/youtube-metadata.js +168 -0
- package/dist/core/youtube-metadata.js.map +1 -0
- package/dist/core/youtube-metadata.test.d.ts +2 -0
- package/dist/core/youtube-metadata.test.d.ts.map +1 -0
- package/dist/core/youtube-metadata.test.js +132 -0
- package/dist/core/youtube-metadata.test.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/prompt-commands.d.ts +24 -0
- package/dist/prompt-commands.d.ts.map +1 -0
- package/dist/prompt-commands.js +243 -0
- package/dist/prompt-commands.js.map +1 -0
- package/dist/prompt-commands.test.d.ts +2 -0
- package/dist/prompt-commands.test.d.ts.map +1 -0
- package/dist/prompt-commands.test.js +46 -0
- package/dist/prompt-commands.test.js.map +1 -0
- package/dist/skills.d.ts +6 -6
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +1426 -445
- package/dist/skills.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +108 -0
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/add-fades.d.ts.map +1 -1
- package/dist/tools/add-fades.js +2 -1
- package/dist/tools/add-fades.js.map +1 -1
- package/dist/tools/add-sfx-at-cuts.d.ts.map +1 -1
- package/dist/tools/add-sfx-at-cuts.js +36 -11
- package/dist/tools/add-sfx-at-cuts.js.map +1 -1
- package/dist/tools/add-sfx-to-timeline.d.ts +34 -0
- package/dist/tools/add-sfx-to-timeline.d.ts.map +1 -0
- package/dist/tools/add-sfx-to-timeline.js +169 -0
- package/dist/tools/add-sfx-to-timeline.js.map +1 -0
- package/dist/tools/add-sfx-to-timeline.test.d.ts +2 -0
- package/dist/tools/add-sfx-to-timeline.test.d.ts.map +1 -0
- package/dist/tools/add-sfx-to-timeline.test.js +181 -0
- package/dist/tools/add-sfx-to-timeline.test.js.map +1 -0
- package/dist/tools/audit-first-frame.d.ts +36 -0
- package/dist/tools/audit-first-frame.d.ts.map +1 -0
- package/dist/tools/audit-first-frame.js +181 -0
- package/dist/tools/audit-first-frame.js.map +1 -0
- package/dist/tools/audit-retention-structure.d.ts +20 -0
- package/dist/tools/audit-retention-structure.d.ts.map +1 -0
- package/dist/tools/audit-retention-structure.js +95 -0
- package/dist/tools/audit-retention-structure.js.map +1 -0
- package/dist/tools/audit-retention-structure.test.d.ts +2 -0
- package/dist/tools/audit-retention-structure.test.d.ts.map +1 -0
- package/dist/tools/audit-retention-structure.test.js +93 -0
- package/dist/tools/audit-retention-structure.test.js.map +1 -0
- package/dist/tools/bleep-words.d.ts +59 -0
- package/dist/tools/bleep-words.d.ts.map +1 -0
- package/dist/tools/bleep-words.js +211 -0
- package/dist/tools/bleep-words.js.map +1 -0
- package/dist/tools/bleep-words.test.d.ts +2 -0
- package/dist/tools/bleep-words.test.d.ts.map +1 -0
- package/dist/tools/bleep-words.test.js +96 -0
- package/dist/tools/bleep-words.test.js.map +1 -0
- package/dist/tools/burn-subtitles.d.ts.map +1 -1
- package/dist/tools/burn-subtitles.js +10 -5
- package/dist/tools/burn-subtitles.js.map +1 -1
- package/dist/tools/clean-audio.d.ts.map +1 -1
- package/dist/tools/clean-audio.js +2 -1
- package/dist/tools/clean-audio.js.map +1 -1
- package/dist/tools/cluster-takes.js +2 -1
- package/dist/tools/cluster-takes.js.map +1 -1
- package/dist/tools/compose-thumbnail-variants.d.ts +70 -0
- package/dist/tools/compose-thumbnail-variants.d.ts.map +1 -0
- package/dist/tools/compose-thumbnail-variants.js +274 -0
- package/dist/tools/compose-thumbnail-variants.js.map +1 -0
- package/dist/tools/compose-thumbnail.d.ts +6 -13
- package/dist/tools/compose-thumbnail.d.ts.map +1 -1
- package/dist/tools/compose-thumbnail.js +44 -81
- package/dist/tools/compose-thumbnail.js.map +1 -1
- package/dist/tools/concat-videos.d.ts.map +1 -1
- package/dist/tools/concat-videos.js +12 -5
- package/dist/tools/concat-videos.js.map +1 -1
- package/dist/tools/concat-videos.test.d.ts +2 -0
- package/dist/tools/concat-videos.test.d.ts.map +1 -0
- package/dist/tools/concat-videos.test.js +103 -0
- package/dist/tools/concat-videos.test.js.map +1 -0
- package/dist/tools/crossfade-videos.d.ts.map +1 -1
- package/dist/tools/crossfade-videos.js +2 -1
- package/dist/tools/crossfade-videos.js.map +1 -1
- package/dist/tools/cut-filler-words.d.ts.map +1 -1
- package/dist/tools/cut-filler-words.js +24 -8
- package/dist/tools/cut-filler-words.js.map +1 -1
- package/dist/tools/detect-speaker-changes.js +2 -1
- package/dist/tools/detect-speaker-changes.js.map +1 -1
- package/dist/tools/extract-audio.d.ts.map +1 -1
- package/dist/tools/extract-audio.js +13 -7
- package/dist/tools/extract-audio.js.map +1 -1
- package/dist/tools/face-reframe.d.ts +30 -0
- package/dist/tools/face-reframe.d.ts.map +1 -0
- package/dist/tools/face-reframe.js +143 -0
- package/dist/tools/face-reframe.js.map +1 -0
- package/dist/tools/face-reframe.test.d.ts +2 -0
- package/dist/tools/face-reframe.test.d.ts.map +1 -0
- package/dist/tools/face-reframe.test.js +139 -0
- package/dist/tools/face-reframe.test.js.map +1 -0
- package/dist/tools/find-viral-moments.d.ts +23 -0
- package/dist/tools/find-viral-moments.d.ts.map +1 -0
- package/dist/tools/find-viral-moments.js +176 -0
- package/dist/tools/find-viral-moments.js.map +1 -0
- package/dist/tools/find-viral-moments.test.d.ts +2 -0
- package/dist/tools/find-viral-moments.test.d.ts.map +1 -0
- package/dist/tools/find-viral-moments.test.js +144 -0
- package/dist/tools/find-viral-moments.test.js.map +1 -0
- package/dist/tools/generate-gif.d.ts.map +1 -1
- package/dist/tools/generate-gif.js +47 -40
- package/dist/tools/generate-gif.js.map +1 -1
- package/dist/tools/generate-gif.test.d.ts +2 -0
- package/dist/tools/generate-gif.test.d.ts.map +1 -0
- package/dist/tools/generate-gif.test.js +115 -0
- package/dist/tools/generate-gif.test.js.map +1 -0
- package/dist/tools/generate-outro.d.ts +18 -0
- package/dist/tools/generate-outro.d.ts.map +1 -0
- package/dist/tools/generate-outro.js +175 -0
- package/dist/tools/generate-outro.js.map +1 -0
- package/dist/tools/generate-youtube-metadata.d.ts +23 -0
- package/dist/tools/generate-youtube-metadata.d.ts.map +1 -0
- package/dist/tools/generate-youtube-metadata.js +103 -0
- package/dist/tools/generate-youtube-metadata.js.map +1 -0
- package/dist/tools/generate-youtube-metadata.test.d.ts +2 -0
- package/dist/tools/generate-youtube-metadata.test.d.ts.map +1 -0
- package/dist/tools/generate-youtube-metadata.test.js +118 -0
- package/dist/tools/generate-youtube-metadata.test.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +130 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/index.test.js +27 -1
- package/dist/tools/index.test.js.map +1 -1
- package/dist/tools/ken-burns.d.ts.map +1 -1
- package/dist/tools/ken-burns.js +2 -1
- package/dist/tools/ken-burns.js.map +1 -1
- package/dist/tools/loop-match-short.d.ts +22 -0
- package/dist/tools/loop-match-short.d.ts.map +1 -0
- package/dist/tools/loop-match-short.js +107 -0
- package/dist/tools/loop-match-short.js.map +1 -0
- package/dist/tools/mix-audio.d.ts.map +1 -1
- package/dist/tools/mix-audio.js +2 -1
- package/dist/tools/mix-audio.js.map +1 -1
- package/dist/tools/normalize-loudness.d.ts.map +1 -1
- package/dist/tools/normalize-loudness.js +2 -1
- package/dist/tools/normalize-loudness.js.map +1 -1
- package/dist/tools/path-traversal.test.d.ts +15 -0
- package/dist/tools/path-traversal.test.d.ts.map +1 -0
- package/dist/tools/path-traversal.test.js +223 -0
- package/dist/tools/path-traversal.test.js.map +1 -0
- package/dist/tools/pick-best-takes.js +2 -1
- package/dist/tools/pick-best-takes.js.map +1 -1
- package/dist/tools/punch-in.d.ts.map +1 -1
- package/dist/tools/punch-in.js +2 -1
- package/dist/tools/punch-in.js.map +1 -1
- package/dist/tools/read-transcript.js +2 -1
- package/dist/tools/read-transcript.js.map +1 -1
- package/dist/tools/render-multi-format.d.ts +35 -0
- package/dist/tools/render-multi-format.d.ts.map +1 -0
- package/dist/tools/render-multi-format.js +206 -0
- package/dist/tools/render-multi-format.js.map +1 -0
- package/dist/tools/render-multi-format.test.d.ts +2 -0
- package/dist/tools/render-multi-format.test.d.ts.map +1 -0
- package/dist/tools/render-multi-format.test.js +312 -0
- package/dist/tools/render-multi-format.test.js.map +1 -0
- package/dist/tools/render.d.ts.map +1 -1
- package/dist/tools/render.js +2 -2
- package/dist/tools/render.js.map +1 -1
- package/dist/tools/rewrite-hook.d.ts +32 -0
- package/dist/tools/rewrite-hook.d.ts.map +1 -0
- package/dist/tools/rewrite-hook.js +65 -0
- package/dist/tools/rewrite-hook.js.map +1 -0
- package/dist/tools/score-clip.d.ts +30 -0
- package/dist/tools/score-clip.d.ts.map +1 -0
- package/dist/tools/score-clip.js +109 -0
- package/dist/tools/score-clip.js.map +1 -0
- package/dist/tools/score-clip.test.d.ts +2 -0
- package/dist/tools/score-clip.test.d.ts.map +1 -0
- package/dist/tools/score-clip.test.js +110 -0
- package/dist/tools/score-clip.test.js.map +1 -0
- package/dist/tools/search-tools.d.ts +34 -0
- package/dist/tools/search-tools.d.ts.map +1 -0
- package/dist/tools/search-tools.js +86 -0
- package/dist/tools/search-tools.js.map +1 -0
- package/dist/tools/search-tools.test.d.ts +2 -0
- package/dist/tools/search-tools.test.d.ts.map +1 -0
- package/dist/tools/search-tools.test.js +60 -0
- package/dist/tools/search-tools.test.js.map +1 -0
- package/dist/tools/snap-cuts-to-beats.d.ts +18 -0
- package/dist/tools/snap-cuts-to-beats.d.ts.map +1 -0
- package/dist/tools/snap-cuts-to-beats.js +110 -0
- package/dist/tools/snap-cuts-to-beats.js.map +1 -0
- package/dist/tools/snap-cuts-to-beats.test.d.ts +2 -0
- package/dist/tools/snap-cuts-to-beats.test.d.ts.map +1 -0
- package/dist/tools/snap-cuts-to-beats.test.js +99 -0
- package/dist/tools/snap-cuts-to-beats.test.js.map +1 -0
- package/dist/tools/speed-ramp.d.ts.map +1 -1
- package/dist/tools/speed-ramp.js +2 -1
- package/dist/tools/speed-ramp.js.map +1 -1
- package/dist/tools/stabilize-video.d.ts.map +1 -1
- package/dist/tools/stabilize-video.js +2 -1
- package/dist/tools/stabilize-video.js.map +1 -1
- package/dist/tools/suggest-broll.d.ts +34 -0
- package/dist/tools/suggest-broll.d.ts.map +1 -0
- package/dist/tools/suggest-broll.js +367 -0
- package/dist/tools/suggest-broll.js.map +1 -0
- package/dist/tools/suggest-broll.test.d.ts +2 -0
- package/dist/tools/suggest-broll.test.d.ts.map +1 -0
- package/dist/tools/suggest-broll.test.js +217 -0
- package/dist/tools/suggest-broll.test.js.map +1 -0
- package/dist/tools/text-based-cut.d.ts +33 -0
- package/dist/tools/text-based-cut.d.ts.map +1 -0
- package/dist/tools/text-based-cut.js +172 -0
- package/dist/tools/text-based-cut.js.map +1 -0
- package/dist/tools/text-based-cut.test.d.ts +2 -0
- package/dist/tools/text-based-cut.test.d.ts.map +1 -0
- package/dist/tools/text-based-cut.test.js +32 -0
- package/dist/tools/text-based-cut.test.js.map +1 -0
- package/dist/tools/transcribe.d.ts +1 -1
- package/dist/tools/transition-videos.d.ts +1 -1
- package/dist/tools/transition-videos.d.ts.map +1 -1
- package/dist/tools/transition-videos.js +2 -1
- package/dist/tools/transition-videos.js.map +1 -1
- package/dist/tools/trim-dead-air.d.ts +59 -0
- package/dist/tools/trim-dead-air.d.ts.map +1 -0
- package/dist/tools/trim-dead-air.js +215 -0
- package/dist/tools/trim-dead-air.js.map +1 -0
- package/dist/tools/trim-dead-air.test.d.ts +2 -0
- package/dist/tools/trim-dead-air.test.d.ts.map +1 -0
- package/dist/tools/trim-dead-air.test.js +75 -0
- package/dist/tools/trim-dead-air.test.js.map +1 -0
- package/dist/tools/verify-thumbnail-promise.d.ts +33 -0
- package/dist/tools/verify-thumbnail-promise.d.ts.map +1 -0
- package/dist/tools/verify-thumbnail-promise.js +112 -0
- package/dist/tools/verify-thumbnail-promise.js.map +1 -0
- package/dist/tools/verify-thumbnail-promise.test.d.ts +2 -0
- package/dist/tools/verify-thumbnail-promise.test.d.ts.map +1 -0
- package/dist/tools/verify-thumbnail-promise.test.js +38 -0
- package/dist/tools/verify-thumbnail-promise.test.js.map +1 -0
- package/dist/tools/write-keyword-captions.d.ts +7 -0
- package/dist/tools/write-keyword-captions.d.ts.map +1 -1
- package/dist/tools/write-keyword-captions.js +35 -4
- package/dist/tools/write-keyword-captions.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +75 -11
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/tool-formatters.d.ts +30 -0
- package/dist/ui/tool-formatters.d.ts.map +1 -0
- package/dist/ui/tool-formatters.js +461 -0
- package/dist/ui/tool-formatters.js.map +1 -0
- package/dist/ui/tool-formatters.test.d.ts +2 -0
- package/dist/ui/tool-formatters.test.d.ts.map +1 -0
- package/dist/ui/tool-formatters.test.js +143 -0
- package/dist/ui/tool-formatters.test.js.map +1 -0
- package/package.json +10 -9
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createAddSfxToTimelineTool } from "./add-sfx-to-timeline.js";
|
|
3
|
+
// Mock bundled-sfx so the tool tests don't try to spawn ffmpeg.
|
|
4
|
+
vi.mock("../core/bundled-sfx.js", async () => {
|
|
5
|
+
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
|
6
|
+
const actual = await vi.importActual("../core/bundled-sfx.js");
|
|
7
|
+
/* eslint-enable @typescript-eslint/consistent-type-imports */
|
|
8
|
+
return {
|
|
9
|
+
...actual,
|
|
10
|
+
resolveSfx: vi.fn(async (name) => {
|
|
11
|
+
if (name === "whoosh") {
|
|
12
|
+
return { path: "/cache/whoosh.wav", bundled: true, name: "whoosh" };
|
|
13
|
+
}
|
|
14
|
+
if (name === "/abs/custom.wav") {
|
|
15
|
+
return { path: "/abs/custom.wav", bundled: false };
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`unknown SFX name: '${name}'. Bundled: pop, whoosh`);
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
const ctx = {
|
|
22
|
+
signal: new AbortController().signal,
|
|
23
|
+
toolCallId: "t1",
|
|
24
|
+
};
|
|
25
|
+
// Loose mock helpers — we don't import the internal types since some
|
|
26
|
+
// (ClipInfo / TimelineState) aren't part of the public type surface.
|
|
27
|
+
function mockHost(opts) {
|
|
28
|
+
const defaultInsert = async ({ recordFrame, track, mediaKind, }) => ({
|
|
29
|
+
id: `clip-${recordFrame}`,
|
|
30
|
+
track: track ?? 3,
|
|
31
|
+
trackKind: (mediaKind ?? "video"),
|
|
32
|
+
startFrame: recordFrame,
|
|
33
|
+
endFrame: recordFrame + 9,
|
|
34
|
+
name: "whoosh.wav",
|
|
35
|
+
});
|
|
36
|
+
const insertSpy = opts.insert ?? defaultInsert;
|
|
37
|
+
return {
|
|
38
|
+
name: "resolve",
|
|
39
|
+
capabilities: () => Promise.resolve({
|
|
40
|
+
isAvailable: true,
|
|
41
|
+
canMoveClips: false,
|
|
42
|
+
canScriptColor: true,
|
|
43
|
+
canScriptAudio: false,
|
|
44
|
+
canTriggerAI: false,
|
|
45
|
+
preferredImportFormat: "edl",
|
|
46
|
+
}),
|
|
47
|
+
getTimeline: () => {
|
|
48
|
+
if (opts.getTimelineErr)
|
|
49
|
+
return Promise.reject(opts.getTimelineErr);
|
|
50
|
+
return Promise.resolve({
|
|
51
|
+
frameRate: opts.fps ?? 30,
|
|
52
|
+
fps: opts.fps ?? 30,
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
insertClipOnTrack: insertSpy,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
describe("add_sfx_to_timeline", () => {
|
|
59
|
+
it("converts seconds to frames using timeline fps and inserts on the requested audio track", async () => {
|
|
60
|
+
const insert = async ({ recordFrame, track, mediaKind, mediaPath, }) => ({
|
|
61
|
+
id: `c-${recordFrame}`,
|
|
62
|
+
track,
|
|
63
|
+
trackKind: (mediaKind ?? "video"),
|
|
64
|
+
startFrame: recordFrame,
|
|
65
|
+
endFrame: recordFrame + 9,
|
|
66
|
+
name: mediaPath.split("/").pop() ?? "x",
|
|
67
|
+
});
|
|
68
|
+
const insertSpy = vi.fn(insert);
|
|
69
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30, insert: insertSpy }), "/cwd");
|
|
70
|
+
const r = await tool.execute({ sfx: "whoosh", cutPoints: [1, 2, 5.5], track: 3 }, ctx);
|
|
71
|
+
const out = JSON.parse(r);
|
|
72
|
+
expect(out.ok).toBe(true);
|
|
73
|
+
expect(out.inserted).toBe(3);
|
|
74
|
+
expect(out.track).toBe(3);
|
|
75
|
+
expect(out.fps).toBe(30);
|
|
76
|
+
expect(out.sfx).toBe("bundled:whoosh");
|
|
77
|
+
// Verify each insertion went via the audio path with correct frame conversion.
|
|
78
|
+
expect(insertSpy).toHaveBeenCalledTimes(3);
|
|
79
|
+
expect(insertSpy).toHaveBeenNthCalledWith(1, {
|
|
80
|
+
mediaPath: "/cache/whoosh.wav",
|
|
81
|
+
track: 3,
|
|
82
|
+
recordFrame: 30,
|
|
83
|
+
mediaKind: "audio",
|
|
84
|
+
});
|
|
85
|
+
expect(insertSpy).toHaveBeenNthCalledWith(2, {
|
|
86
|
+
mediaPath: "/cache/whoosh.wav",
|
|
87
|
+
track: 3,
|
|
88
|
+
recordFrame: 60,
|
|
89
|
+
mediaKind: "audio",
|
|
90
|
+
});
|
|
91
|
+
expect(insertSpy).toHaveBeenNthCalledWith(3, {
|
|
92
|
+
mediaPath: "/cache/whoosh.wav",
|
|
93
|
+
track: 3,
|
|
94
|
+
recordFrame: 165,
|
|
95
|
+
mediaKind: "audio",
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
it("dedupes cuts closer than minSpacingSec", async () => {
|
|
99
|
+
const insert = vi.fn(async () => ({
|
|
100
|
+
id: "c",
|
|
101
|
+
track: 3,
|
|
102
|
+
trackKind: "audio",
|
|
103
|
+
startFrame: 0,
|
|
104
|
+
endFrame: 9,
|
|
105
|
+
name: "w",
|
|
106
|
+
}));
|
|
107
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30, insert }), "/cwd");
|
|
108
|
+
await tool.execute({ sfx: "whoosh", cutPoints: [1, 1.05, 1.1, 5], minSpacingSec: 0.25 }, ctx);
|
|
109
|
+
expect(insert).toHaveBeenCalledTimes(2); // 1.0 and 5.0 only
|
|
110
|
+
});
|
|
111
|
+
it("uses default track A3 when not specified", async () => {
|
|
112
|
+
const insert = vi.fn(async () => ({
|
|
113
|
+
id: "c",
|
|
114
|
+
track: 3,
|
|
115
|
+
trackKind: "audio",
|
|
116
|
+
startFrame: 0,
|
|
117
|
+
endFrame: 9,
|
|
118
|
+
name: "w",
|
|
119
|
+
}));
|
|
120
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30, insert }), "/cwd");
|
|
121
|
+
await tool.execute({ sfx: "whoosh", cutPoints: [1] }, ctx);
|
|
122
|
+
expect(insert).toHaveBeenCalledWith(expect.objectContaining({ track: 3, mediaKind: "audio" }));
|
|
123
|
+
});
|
|
124
|
+
it("fails clean with a host hint when the audio track doesn't exist", async () => {
|
|
125
|
+
const insert = async () => {
|
|
126
|
+
throw new Error("track 7 does not exist on active sequence.");
|
|
127
|
+
};
|
|
128
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30, insert }), "/cwd");
|
|
129
|
+
const r = await tool.execute({ sfx: "whoosh", cutPoints: [1, 2], track: 7 }, ctx);
|
|
130
|
+
expect(r).toMatch(/^error:/);
|
|
131
|
+
expect(r).toMatch(/add_track\(kind='audio'\)/);
|
|
132
|
+
});
|
|
133
|
+
it("partial-success: some inserts fail, returns ok with failures detail", async () => {
|
|
134
|
+
let n = 0;
|
|
135
|
+
const insert = async ({ recordFrame }) => {
|
|
136
|
+
n++;
|
|
137
|
+
if (n === 2)
|
|
138
|
+
throw new Error("transient bridge error");
|
|
139
|
+
return {
|
|
140
|
+
id: `c-${recordFrame}`,
|
|
141
|
+
track: 3,
|
|
142
|
+
trackKind: "audio",
|
|
143
|
+
startFrame: recordFrame,
|
|
144
|
+
endFrame: recordFrame + 9,
|
|
145
|
+
name: "w",
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30, insert }), "/cwd");
|
|
149
|
+
const r = await tool.execute({ sfx: "whoosh", cutPoints: [1, 2, 3] }, ctx);
|
|
150
|
+
const out = JSON.parse(r);
|
|
151
|
+
expect(out.inserted).toBe(2);
|
|
152
|
+
expect(out.failed).toBe(1);
|
|
153
|
+
});
|
|
154
|
+
it("respects explicit frameRate override", async () => {
|
|
155
|
+
const insert = async ({ recordFrame }) => ({
|
|
156
|
+
id: `c-${recordFrame}`,
|
|
157
|
+
track: 3,
|
|
158
|
+
trackKind: "audio",
|
|
159
|
+
startFrame: recordFrame,
|
|
160
|
+
endFrame: recordFrame + 9,
|
|
161
|
+
name: "w",
|
|
162
|
+
});
|
|
163
|
+
const insertSpy = vi.fn(insert);
|
|
164
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30, insert: insertSpy }), "/cwd");
|
|
165
|
+
await tool.execute({ sfx: "whoosh", cutPoints: [1], frameRate: 60 }, ctx);
|
|
166
|
+
expect(insertSpy).toHaveBeenCalledWith(expect.objectContaining({ recordFrame: 60 }));
|
|
167
|
+
});
|
|
168
|
+
it("propagates unknown SFX name errors with the bundled list in the hint", async () => {
|
|
169
|
+
const tool = createAddSfxToTimelineTool(mockHost({ fps: 30 }), "/cwd");
|
|
170
|
+
const r = await tool.execute({ sfx: "notarealsfx", cutPoints: [1] }, ctx);
|
|
171
|
+
expect(r).toMatch(/error: unknown SFX name/);
|
|
172
|
+
expect(r).toMatch(/bundled SFX name/);
|
|
173
|
+
});
|
|
174
|
+
it("rejects when the host can't report a frame rate", async () => {
|
|
175
|
+
const tool = createAddSfxToTimelineTool(mockHost({ getTimelineErr: new Error("host=none") }), "/cwd");
|
|
176
|
+
const r = await tool.execute({ sfx: "whoosh", cutPoints: [1] }, ctx);
|
|
177
|
+
expect(r).toMatch(/cannot read timeline framerate/);
|
|
178
|
+
expect(r).toMatch(/frameRate=/);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=add-sfx-to-timeline.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-sfx-to-timeline.test.js","sourceRoot":"","sources":["../../src/tools/add-sfx-to-timeline.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AgentTool } from "@kenkaiiii/gg-agent";
|
|
3
|
+
declare const AuditFirstFrameParams: z.ZodObject<{
|
|
4
|
+
input: z.ZodString;
|
|
5
|
+
detail: z.ZodOptional<z.ZodEnum<{
|
|
6
|
+
low: "low";
|
|
7
|
+
high: "high";
|
|
8
|
+
}>>;
|
|
9
|
+
model: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
interface FirstFrameVisionResponse {
|
|
12
|
+
score: number;
|
|
13
|
+
hasFace: boolean;
|
|
14
|
+
faceProminent: boolean;
|
|
15
|
+
hasReadableText: boolean;
|
|
16
|
+
hasClearSubject: boolean;
|
|
17
|
+
hasMotion: boolean;
|
|
18
|
+
mode: "static-logo" | "cold-open-load" | "face-blink" | "usable" | "strong";
|
|
19
|
+
findings: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* audit_first_frame — score t=0.0s as if it were the thumbnail.
|
|
23
|
+
*
|
|
24
|
+
* Per Hoyos / Galloway: "treat the first frame like a thumbnail."
|
|
25
|
+
* Autoplay surfaces the first frame BEFORE audio loads, so a logo slate
|
|
26
|
+
* or cold-open hold tanks retention before viewers ever hear the hook.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createAuditFirstFrameTool(cwd: string): AgentTool<typeof AuditFirstFrameParams>;
|
|
29
|
+
/**
|
|
30
|
+
* Parse the model's JSON response. Robust to missing keys / weird types
|
|
31
|
+
* — never throws as long as the JSON itself is valid. Pure — exported
|
|
32
|
+
* for testing.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseFirstFrameResponse(content: string): FirstFrameVisionResponse;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=audit-first-frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-first-frame.d.ts","sourceRoot":"","sources":["../../src/tools/audit-first-frame.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMrD,QAAA,MAAM,qBAAqB;;;;;;;iBAIzB,CAAC;AA+BH,UAAU,wBAAwB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,aAAa,GAAG,gBAAgB,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,qBAAqB,CAAC,CAmD9F;AAwDD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,wBAAwB,CA6BjF"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve as resolvePath } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { resolveApiKey } from "../core/auth/api-keys.js";
|
|
5
|
+
import { compact, err } from "../core/format.js";
|
|
6
|
+
import { extractAtTimes } from "../core/frames.js";
|
|
7
|
+
import { checkFfmpeg, probeMedia } from "../core/media/ffmpeg.js";
|
|
8
|
+
const AuditFirstFrameParams = z.object({
|
|
9
|
+
input: z.string().describe("Source video (relative resolves to cwd)."),
|
|
10
|
+
detail: z.enum(["low", "high"]).optional().describe("Vision detail. Default low."),
|
|
11
|
+
model: z.string().optional().describe("OpenAI model. Default gpt-4o-mini."),
|
|
12
|
+
});
|
|
13
|
+
const VISION_SYSTEM = `You score a SINGLE FRAME (the first frame of a YouTube video) AS IF it were the thumbnail at 100x56 mobile-feed scale. Autoplay shows this frame BEFORE audio loads — if it looks like a logo slate, a black hold, or a mid-blink face, the viewer scrolls.
|
|
14
|
+
|
|
15
|
+
Output a JSON object with these EXACT keys:
|
|
16
|
+
{
|
|
17
|
+
"score": <0..100 integer>,
|
|
18
|
+
"hasFace": <bool>,
|
|
19
|
+
"faceProminent": <bool>, // face fills ≥ ~20% of frame area
|
|
20
|
+
"hasReadableText": <bool>, // any large legible text (hook line, label)
|
|
21
|
+
"hasClearSubject": <bool>, // a single obvious focal point
|
|
22
|
+
"hasMotion": <bool>, // not strictly possible from one frame; mark true only when blur / streak / mid-action implies motion
|
|
23
|
+
"mode": "static-logo"|"cold-open-load"|"face-blink"|"usable"|"strong",
|
|
24
|
+
"findings": [<string>, ...] // 1-4 short findings (≤120 chars each)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Scoring rubric:
|
|
28
|
+
85-100: STRONG — clear subject, expressive face, color contrast, readable text, no logo slate.
|
|
29
|
+
60-84: USABLE — subject present, decent contrast, no obvious blockers.
|
|
30
|
+
30-59: WEAK — abstract pattern, small subject, soft contrast, mid-blink, or pre-roll filler.
|
|
31
|
+
0-29: FAIL — black slate, plain logo card, glitch frame, mid-blink face, totally unreadable.
|
|
32
|
+
|
|
33
|
+
Modes:
|
|
34
|
+
static-logo = a logo card / channel branding slate
|
|
35
|
+
cold-open-load = a near-black or solid-color frame (intro hasn't started)
|
|
36
|
+
face-blink = a face mid-blink / mid-word / awkward expression
|
|
37
|
+
usable = nothing wrong but nothing exceptional either
|
|
38
|
+
strong = thumbnail-ready opening frame
|
|
39
|
+
|
|
40
|
+
Be honest — this rubric exists so the creator knows when to recut their first frame.`;
|
|
41
|
+
/**
|
|
42
|
+
* audit_first_frame — score t=0.0s as if it were the thumbnail.
|
|
43
|
+
*
|
|
44
|
+
* Per Hoyos / Galloway: "treat the first frame like a thumbnail."
|
|
45
|
+
* Autoplay surfaces the first frame BEFORE audio loads, so a logo slate
|
|
46
|
+
* or cold-open hold tanks retention before viewers ever hear the hook.
|
|
47
|
+
*/
|
|
48
|
+
export function createAuditFirstFrameTool(cwd) {
|
|
49
|
+
return {
|
|
50
|
+
name: "audit_first_frame",
|
|
51
|
+
description: "Score the first frame of a video as if it were the thumbnail at 100×56 mobile-feed " +
|
|
52
|
+
"scale. Per Galloway / Hoyos: 'treat your intro like a thumbnail' — autoplay shows the " +
|
|
53
|
+
"first frame BEFORE audio loads, so logo slates and cold-open holds tank retention. " +
|
|
54
|
+
"Penalises static-logo, cold-open-load, face-blink modes; rewards a clear subject + " +
|
|
55
|
+
"expressive face + readable hook text. Pair with `audit_retention_structure` and " +
|
|
56
|
+
"`analyze_hook` as the three short-form pre-render checks. Returns score 0-100 + " +
|
|
57
|
+
"findings + mode.",
|
|
58
|
+
parameters: AuditFirstFrameParams,
|
|
59
|
+
async execute(args, ctx) {
|
|
60
|
+
if (!checkFfmpeg())
|
|
61
|
+
return err("ffmpeg not on PATH", "install ffmpeg");
|
|
62
|
+
const apiKey = resolveApiKey("OPENAI_API_KEY", "openai");
|
|
63
|
+
if (!apiKey)
|
|
64
|
+
return err("OPENAI_API_KEY not set", "export OPENAI_API_KEY=...");
|
|
65
|
+
try {
|
|
66
|
+
const inAbs = resolvePath(cwd, args.input);
|
|
67
|
+
const probe = probeMedia(inAbs);
|
|
68
|
+
if (!probe)
|
|
69
|
+
return err(`probe failed for ${inAbs}`, "verify file exists and is media");
|
|
70
|
+
const frames = await extractAtTimes(inAbs, [0], {
|
|
71
|
+
maxWidth: 768,
|
|
72
|
+
signal: ctx.signal,
|
|
73
|
+
});
|
|
74
|
+
if (frames.length === 0) {
|
|
75
|
+
return err("could not extract first frame", "verify the input is a readable video");
|
|
76
|
+
}
|
|
77
|
+
const vision = await runFirstFrameVision(frames[0].path, {
|
|
78
|
+
apiKey,
|
|
79
|
+
model: args.model,
|
|
80
|
+
detail: args.detail,
|
|
81
|
+
signal: ctx.signal,
|
|
82
|
+
});
|
|
83
|
+
return compact({
|
|
84
|
+
score: vision.score,
|
|
85
|
+
mode: vision.mode,
|
|
86
|
+
hasFace: vision.hasFace,
|
|
87
|
+
faceProminent: vision.faceProminent,
|
|
88
|
+
hasReadableText: vision.hasReadableText,
|
|
89
|
+
hasClearSubject: vision.hasClearSubject,
|
|
90
|
+
hasMotion: vision.hasMotion,
|
|
91
|
+
findings: vision.findings,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
return err(e.message);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function runFirstFrameVision(framePath, opts) {
|
|
101
|
+
const b64 = readFileSync(framePath).toString("base64");
|
|
102
|
+
const detail = opts.detail ?? "low";
|
|
103
|
+
const model = opts.model ?? "gpt-4o-mini";
|
|
104
|
+
const body = {
|
|
105
|
+
model,
|
|
106
|
+
messages: [
|
|
107
|
+
{ role: "system", content: VISION_SYSTEM },
|
|
108
|
+
{
|
|
109
|
+
role: "user",
|
|
110
|
+
content: [
|
|
111
|
+
{ type: "text", text: "FIRST FRAME (t=0):" },
|
|
112
|
+
{
|
|
113
|
+
type: "image_url",
|
|
114
|
+
image_url: { url: `data:image/jpeg;base64,${b64}`, detail },
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
response_format: { type: "json_object" },
|
|
120
|
+
max_tokens: 2000,
|
|
121
|
+
temperature: 0,
|
|
122
|
+
};
|
|
123
|
+
const res = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
124
|
+
method: "POST",
|
|
125
|
+
headers: {
|
|
126
|
+
Authorization: `Bearer ${opts.apiKey}`,
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
},
|
|
129
|
+
body: JSON.stringify(body),
|
|
130
|
+
signal: opts.signal,
|
|
131
|
+
});
|
|
132
|
+
if (!res.ok) {
|
|
133
|
+
const text = await res.text().catch(() => "");
|
|
134
|
+
throw new Error(`OpenAI HTTP ${res.status}: ${text.slice(0, 200)}`);
|
|
135
|
+
}
|
|
136
|
+
const data = (await res.json());
|
|
137
|
+
const content = data.choices[0]?.message?.content;
|
|
138
|
+
if (!content)
|
|
139
|
+
throw new Error("audit_first_frame: empty model response");
|
|
140
|
+
return parseFirstFrameResponse(content);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Parse the model's JSON response. Robust to missing keys / weird types
|
|
144
|
+
* — never throws as long as the JSON itself is valid. Pure — exported
|
|
145
|
+
* for testing.
|
|
146
|
+
*/
|
|
147
|
+
export function parseFirstFrameResponse(content) {
|
|
148
|
+
const start = content.indexOf("{");
|
|
149
|
+
const end = content.lastIndexOf("}");
|
|
150
|
+
if (start < 0 || end < start) {
|
|
151
|
+
throw new Error("audit_first_frame: no JSON object in response");
|
|
152
|
+
}
|
|
153
|
+
const parsed = JSON.parse(content.slice(start, end + 1));
|
|
154
|
+
const modeRaw = String(parsed.mode ?? "usable");
|
|
155
|
+
const mode = (["static-logo", "cold-open-load", "face-blink", "usable", "strong"].includes(modeRaw)
|
|
156
|
+
? modeRaw
|
|
157
|
+
: "usable");
|
|
158
|
+
const findings = Array.isArray(parsed.findings)
|
|
159
|
+
? parsed.findings
|
|
160
|
+
.map((v) => String(v ?? "").slice(0, 200))
|
|
161
|
+
.filter((v) => v.length > 0)
|
|
162
|
+
.slice(0, 8)
|
|
163
|
+
: [];
|
|
164
|
+
return {
|
|
165
|
+
score: clampScore(parsed.score),
|
|
166
|
+
hasFace: Boolean(parsed.hasFace),
|
|
167
|
+
faceProminent: Boolean(parsed.faceProminent),
|
|
168
|
+
hasReadableText: Boolean(parsed.hasReadableText),
|
|
169
|
+
hasClearSubject: Boolean(parsed.hasClearSubject),
|
|
170
|
+
hasMotion: Boolean(parsed.hasMotion),
|
|
171
|
+
mode,
|
|
172
|
+
findings,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function clampScore(v) {
|
|
176
|
+
const n = typeof v === "number" ? v : Number(v);
|
|
177
|
+
if (!Number.isFinite(n))
|
|
178
|
+
return 0;
|
|
179
|
+
return Math.max(0, Math.min(100, Math.round(n)));
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=audit-first-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-first-frame.js","sourceRoot":"","sources":["../../src/tools/audit-first-frame.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AgentTool } from "@kenkaiiii/gg-agent";
|
|
3
|
+
declare const AuditRetentionStructureParams: z.ZodObject<{
|
|
4
|
+
transcript: z.ZodString;
|
|
5
|
+
durationSec: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
checkpoints: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
7
|
+
model: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
/**
|
|
10
|
+
* audit_retention_structure — long-form retention checkpoint auditor.
|
|
11
|
+
*
|
|
12
|
+
* Per MrBeast's documented manual, every ~3 minutes a re-engagement is
|
|
13
|
+
* required to keep retention from collapsing. This tool builds a 60s
|
|
14
|
+
* window around each requested checkpoint, asks the LLM to score
|
|
15
|
+
* whether re-engagement is happening, and reports the weakest one so
|
|
16
|
+
* the agent knows where to insert b-roll, punch-ins, or a recut.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createAuditRetentionStructureTool(cwd: string): AgentTool<typeof AuditRetentionStructureParams>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=audit-retention-structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-retention-structure.d.ts","sourceRoot":"","sources":["../../src/tools/audit-retention-structure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMrD,QAAA,MAAM,6BAA6B;;;;;iBAqBjC,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAC/C,GAAG,EAAE,MAAM,GACV,SAAS,CAAC,OAAO,6BAA6B,CAAC,CAiEjD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve as resolvePath } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { compact, err } from "../core/format.js";
|
|
5
|
+
import { runRetentionAudit } from "../core/retention-structure.js";
|
|
6
|
+
import { parseTranscript } from "../core/whisper.js";
|
|
7
|
+
const AuditRetentionStructureParams = z.object({
|
|
8
|
+
transcript: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe("Path to a transcript JSON written by `transcribe`. Segments required."),
|
|
11
|
+
durationSec: z
|
|
12
|
+
.number()
|
|
13
|
+
.positive()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("Override transcript.durationSec — useful when you trust the ffprobe duration over the " +
|
|
16
|
+
"transcript's reported one."),
|
|
17
|
+
checkpoints: z
|
|
18
|
+
.array(z.number().positive())
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Checkpoints to audit (seconds). Default [180, 360] — the 3-min and 6-min " +
|
|
21
|
+
"re-engagement marks. For a 12+ min video pass [180, 360, 540, 720]. Each becomes a " +
|
|
22
|
+
"60s window centred on the timestamp."),
|
|
23
|
+
model: z.string().optional().describe("OpenAI model. Default gpt-4o-mini."),
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* audit_retention_structure — long-form retention checkpoint auditor.
|
|
27
|
+
*
|
|
28
|
+
* Per MrBeast's documented manual, every ~3 minutes a re-engagement is
|
|
29
|
+
* required to keep retention from collapsing. This tool builds a 60s
|
|
30
|
+
* window around each requested checkpoint, asks the LLM to score
|
|
31
|
+
* whether re-engagement is happening, and reports the weakest one so
|
|
32
|
+
* the agent knows where to insert b-roll, punch-ins, or a recut.
|
|
33
|
+
*/
|
|
34
|
+
export function createAuditRetentionStructureTool(cwd) {
|
|
35
|
+
return {
|
|
36
|
+
name: "audit_retention_structure",
|
|
37
|
+
description: "Audit a long-form video transcript for retention checkpoints (3-min, 6-min " +
|
|
38
|
+
"re-engagements per MrBeast's documented method) and overall escalation pattern. Each " +
|
|
39
|
+
"checkpoint scored 0-1 with a one-line suggestion when weak. Pair with the " +
|
|
40
|
+
"youtube-algorithm-primer skill — viewers drop hardest at flat stretches between " +
|
|
41
|
+
"minutes 1-7. Returns checkpoints[], escalationScore, and weakestCheckpoint so the " +
|
|
42
|
+
"agent knows where to insert b-roll, punch-ins, or re-cut. Requires `transcribe` first.",
|
|
43
|
+
parameters: AuditRetentionStructureParams,
|
|
44
|
+
async execute(args, ctx) {
|
|
45
|
+
try {
|
|
46
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
47
|
+
return err("OPENAI_API_KEY not set", "export OPENAI_API_KEY=...");
|
|
48
|
+
}
|
|
49
|
+
const transcriptAbs = resolvePath(cwd, args.transcript);
|
|
50
|
+
let raw;
|
|
51
|
+
try {
|
|
52
|
+
raw = readFileSync(transcriptAbs, "utf8");
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
return err(`cannot read transcript ${transcriptAbs}: ${e.message}`, "verify the transcript JSON exists");
|
|
56
|
+
}
|
|
57
|
+
let t;
|
|
58
|
+
try {
|
|
59
|
+
t = parseTranscript(raw);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
return err(e.message);
|
|
63
|
+
}
|
|
64
|
+
if (t.segments.length === 0) {
|
|
65
|
+
return err("transcript has no segments", "rerun transcribe(...)");
|
|
66
|
+
}
|
|
67
|
+
const totalSec = args.durationSec ?? t.durationSec;
|
|
68
|
+
if (!totalSec || totalSec <= 0) {
|
|
69
|
+
return err("transcript has zero duration", "pass durationSec explicitly");
|
|
70
|
+
}
|
|
71
|
+
const result = await runRetentionAudit(t, {
|
|
72
|
+
model: args.model,
|
|
73
|
+
checkpoints: args.checkpoints,
|
|
74
|
+
durationSec: totalSec,
|
|
75
|
+
signal: ctx.signal,
|
|
76
|
+
});
|
|
77
|
+
return compact({
|
|
78
|
+
checkpoints: result.checkpoints.map((c) => ({
|
|
79
|
+
atSec: c.atSec,
|
|
80
|
+
score: +c.score.toFixed(2),
|
|
81
|
+
summary: c.summary,
|
|
82
|
+
...(c.suggestion ? { suggestion: c.suggestion } : {}),
|
|
83
|
+
})),
|
|
84
|
+
escalationScore: +result.escalationScore.toFixed(2),
|
|
85
|
+
overallSummary: result.overallSummary,
|
|
86
|
+
weakestCheckpoint: result.weakestCheckpoint,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
return err(e.message);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=audit-retention-structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-retention-structure.js","sourceRoot":"","sources":["../../src/tools/audit-retention-structure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-retention-structure.test.d.ts","sourceRoot":"","sources":["../../src/tools/audit-retention-structure.test.ts"],"names":[],"mappings":""}
|