@hugpy/video-intelligence-ui 0.1.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.
Files changed (177) hide show
  1. package/LICENSE +41 -0
  2. package/assets/sampels/images/bycycle/bd8603bad35d4f179f4d1134d8faf2ee.mp4 +0 -0
  3. package/assets/sampels/images/bycycle/frame_00000.png +0 -0
  4. package/assets/sampels/images/bycycle/frame_00001.png +0 -0
  5. package/assets/sampels/images/bycycle/frame_00002.png +0 -0
  6. package/assets/sampels/images/bycycle/frame_00003.png +0 -0
  7. package/assets/sampels/images/bycycle/frame_00004.png +0 -0
  8. package/assets/sampels/images/bycycle/frame_00005.png +0 -0
  9. package/assets/sampels/images/forrest/ff23090611b844a6b85c224f388bd542.mp4 +0 -0
  10. package/assets/sampels/images/forrest/frame_00000.png +0 -0
  11. package/assets/sampels/images/forrest/frame_00001.png +0 -0
  12. package/assets/sampels/images/forrest/frame_00002.png +0 -0
  13. package/assets/sampels/images/forrest/frame_00003.png +0 -0
  14. package/assets/sampels/images/forrest/frame_00004.png +0 -0
  15. package/assets/sampels/images/forrest/frame_00005.png +0 -0
  16. package/assets/sampels/images/shenzo/e1a4fcd623084ab4a986d11c8cd00db8.mp4 +0 -0
  17. package/assets/sampels/images/shenzo/frame_00000.png +0 -0
  18. package/assets/sampels/images/shenzo/frame_00001.png +0 -0
  19. package/assets/sampels/images/shenzo/frame_00002.png +0 -0
  20. package/assets/sampels/images/shenzo/frame_00003.png +0 -0
  21. package/assets/sampels/images/shenzo/frame_00004.png +0 -0
  22. package/assets/sampels/images/shenzo/frame_00005.png +0 -0
  23. package/assets/sampels/scenes/man.mp4 +0 -0
  24. package/assets/sampels/scenes/woman.mp4 +0 -0
  25. package/assets/sampels/studio_movies/caverns/_assembly/contrib_00.mp4 +0 -0
  26. package/assets/sampels/studio_movies/caverns/movie.json +67 -0
  27. package/assets/sampels/studio_movies/caverns/movie.mp4 +0 -0
  28. package/assets/sampels/studio_movies/caverns/segment_00/5eea7770a554fef0c3bdc38f8f38b925dcf75f13c015d423e8eadec47d41bf6b/clip.mp4 +0 -0
  29. package/assets/sampels/studio_movies/caverns/segment_00/5eea7770a554fef0c3bdc38f8f38b925dcf75f13c015d423e8eadec47d41bf6b/manifest.json +87 -0
  30. package/assets/sampels/studio_movies/caverns/segment_00/5eea7770a554fef0c3bdc38f8f38b925dcf75f13c015d423e8eadec47d41bf6b/provenance.json +7 -0
  31. package/assets/sampels/studio_movies/caverns/segment_01/branch.png +0 -0
  32. package/assets/sampels/studio_movies/keeper-matrix/_assembly/concat_list.txt +2 -0
  33. package/assets/sampels/studio_movies/keeper-matrix/_assembly/contrib_00.mp4 +0 -0
  34. package/assets/sampels/studio_movies/keeper-matrix/_assembly/contrib_01.mp4 +0 -0
  35. package/assets/sampels/studio_movies/keeper-matrix/movie.json +81 -0
  36. package/assets/sampels/studio_movies/keeper-matrix/movie.mp4 +0 -0
  37. package/assets/sampels/studio_movies/keeper-matrix/segment_00/64854c6a21d47ce10b23e884e12de448b25bfb0a375d33238dd0bec8056c076d/clip.mp4 +0 -0
  38. package/assets/sampels/studio_movies/keeper-matrix/segment_00/64854c6a21d47ce10b23e884e12de448b25bfb0a375d33238dd0bec8056c076d/manifest.json +87 -0
  39. package/assets/sampels/studio_movies/keeper-matrix/segment_00/64854c6a21d47ce10b23e884e12de448b25bfb0a375d33238dd0bec8056c076d/provenance.json +7 -0
  40. package/assets/sampels/studio_movies/keeper-matrix/segment_01/branch.png +0 -0
  41. package/assets/sampels/studio_movies/keeper-matrix/segment_01/cc926b44a42b90d7d291a4e50e3859458306c207a17c718086a3466e4049d6c6/clip.mp4 +0 -0
  42. package/assets/sampels/studio_movies/keeper-matrix/segment_01/cc926b44a42b90d7d291a4e50e3859458306c207a17c718086a3466e4049d6c6/manifest.json +87 -0
  43. package/assets/sampels/studio_movies/keeper-matrix/segment_01/cc926b44a42b90d7d291a4e50e3859458306c207a17c718086a3466e4049d6c6/provenance.json +7 -0
  44. package/assets/sampels/videos/a_red_paper_boat_drifting_on_a_calm_pond__gentle_ripples__mo_a62d6c28.mp4 +0 -0
  45. package/assets/sampels/videos/aurora.mp4 +0 -0
  46. package/assets/sampels/videos/dark_night.mp4 +0 -0
  47. package/assets/sampels/videos/fire_and_soul.mp4 +0 -0
  48. package/assets/sampels/videos/harsh_seas.mp4 +0 -0
  49. package/entry.tsx +74 -0
  50. package/index.html +53 -0
  51. package/package.json +42 -0
  52. package/src/assets/hugpy-mark.png +0 -0
  53. package/src/config.ts +676 -0
  54. package/src/demo/DemoBanner.tsx +54 -0
  55. package/src/demo/assets/demo-audio.mp3 +0 -0
  56. package/src/demo/assets/demo-clip.mp4 +0 -0
  57. package/src/demo/assets/demo-crop.mp4 +0 -0
  58. package/src/demo/assets/demo-poster.jpg +0 -0
  59. package/src/demo/assets/frame-1.jpg +0 -0
  60. package/src/demo/assets/frame-2.jpg +0 -0
  61. package/src/demo/assets/frame-3.jpg +0 -0
  62. package/src/demo/assets/frame-4.jpg +0 -0
  63. package/src/demo/assets/frame-5.jpg +0 -0
  64. package/src/demo/assets/frame-6.jpg +0 -0
  65. package/src/demo/assets/gen-1.jpg +0 -0
  66. package/src/demo/assets/gen-2.jpg +0 -0
  67. package/src/demo/assets.d.ts +14 -0
  68. package/src/demo/demo.css +64 -0
  69. package/src/demo/demoFetch.ts +305 -0
  70. package/src/demo/fixtures.ts +814 -0
  71. package/src/demo/index.ts +43 -0
  72. package/src/demo/mode.ts +81 -0
  73. package/src/demo/promptAssist.ts +181 -0
  74. package/src/demo/seed.ts +97 -0
  75. package/src/nav/BrandMark.css +66 -0
  76. package/src/nav/BrandMark.tsx +40 -0
  77. package/src/nav/Navbar.css +13 -0
  78. package/src/nav/Navbar.tsx +68 -0
  79. package/src/regions/SpatialRegionEditor.tsx +375 -0
  80. package/src/regions/TemporalRegionEditor.tsx +485 -0
  81. package/src/regions/types.ts +85 -0
  82. package/src/session.ts +85 -0
  83. package/src/share.ts +77 -0
  84. package/src/stations/ActivePanel.tsx +55 -0
  85. package/src/stations/ActiveProcessesStation.tsx +272 -0
  86. package/src/stations/ActiveProcessesStation.tsx.bak-sessions-20260812 +228 -0
  87. package/src/stations/AddFileBar.tsx +59 -0
  88. package/src/stations/AudioCropStation.tsx +157 -0
  89. package/src/stations/ComfyPanel.tsx +210 -0
  90. package/src/stations/ComfyStation.tsx +196 -0
  91. package/src/stations/CondensedKnobStrip.tsx +245 -0
  92. package/src/stations/ConsolePanel.tsx +82 -0
  93. package/src/stations/FrameExtractStation.tsx +148 -0
  94. package/src/stations/GenIdentityBar.tsx +412 -0
  95. package/src/stations/GenerateStation.tsx +5603 -0
  96. package/src/stations/GenerateStation.tsx.bak-tester-removal +5170 -0
  97. package/src/stations/GoalComposer.tsx +139 -0
  98. package/src/stations/ImageCropStation.tsx +153 -0
  99. package/src/stations/KnobInfo.tsx +64 -0
  100. package/src/stations/PlaceholderStation.tsx +26 -0
  101. package/src/stations/SectionTabs.tsx +276 -0
  102. package/src/stations/SharePanel.tsx +298 -0
  103. package/src/stations/SidebarRegistry.tsx +105 -0
  104. package/src/stations/StationShell.tsx +96 -0
  105. package/src/stations/StudioClipsStation.tsx +28 -0
  106. package/src/stations/WorkbenchDrawer.tsx +66 -0
  107. package/src/stations/WorkbenchSidebar.tsx +1224 -0
  108. package/src/stations/WorkbenchStation.tsx +91 -0
  109. package/src/stations/comfyEmbed.ts +79 -0
  110. package/src/stations/drawerShell.tsx +419 -0
  111. package/src/stations/ops/AudioCropCore.tsx +218 -0
  112. package/src/stations/ops/CharacterGroupsPanel.tsx +716 -0
  113. package/src/stations/ops/FrameExtractCore.tsx +695 -0
  114. package/src/stations/ops/ImageCropCore.tsx +164 -0
  115. package/src/stations/ops/VideoCropCore.tsx +193 -0
  116. package/src/stations/ops/useVideoCropJobs.ts +224 -0
  117. package/src/stations/pollCaps.ts +87 -0
  118. package/src/stations/registry.ts +191 -0
  119. package/src/stations/studio/AngleRingEditor.tsx +159 -0
  120. package/src/stations/studio/IdentitiesStation.tsx +2455 -0
  121. package/src/stations/studio/IdentityProfileControls.tsx +262 -0
  122. package/src/stations/studio/StudioActiveProcesses.tsx +224 -0
  123. package/src/stations/studio/StudioAssistLogPanel.tsx +220 -0
  124. package/src/stations/studio/StudioGenerateMode.tsx +29 -0
  125. package/src/stations/studio/StudioGenerateTab.tsx +2688 -0
  126. package/src/stations/studio/StudioItemCard.tsx +334 -0
  127. package/src/stations/studio/StudioLibraryTab.tsx +506 -0
  128. package/src/stations/studio/StudioMovieComposer.tsx +2875 -0
  129. package/src/stations/studio/StudioMovieComposer.tsx.bak-sessions-20260812 +2729 -0
  130. package/src/stations/studio/StudioMovieSessions.tsx +553 -0
  131. package/src/stations/studio/StudioMovieSessions.tsx.bak-sessions-20260812 +417 -0
  132. package/src/stations/studio/StudioPlane.tsx +302 -0
  133. package/src/stations/studio/StudioSplicedRow.tsx +476 -0
  134. package/src/stations/studio/StudioViewer.tsx +339 -0
  135. package/src/stations/studio/TurntableViewer.tsx +220 -0
  136. package/src/stations/studio/movieTimeline.ts +198 -0
  137. package/src/stations/studio/promptCard.tsx +498 -0
  138. package/src/stations/studio/studioItem.ts +87 -0
  139. package/src/stations/studio/studioShared.tsx +821 -0
  140. package/src/stations/studio/useIdentityProfiles.ts +575 -0
  141. package/src/stations/studio/useReconstruction.ts +283 -0
  142. package/src/stations/types.ts +43 -0
  143. package/src/stations/useAudioCropJobs.ts +202 -0
  144. package/src/stations/useAudioExtractJob.ts +144 -0
  145. package/src/stations/useCropJobs.ts +206 -0
  146. package/src/stations/useFrameJobs.ts +140 -0
  147. package/src/stations/useGenerateJob.ts +151 -0
  148. package/src/stations/useGenerateMovieJob.ts +177 -0
  149. package/src/stations/useGenerateRowJobs.ts +184 -0
  150. package/src/stations/useGenerateSceneJob.ts +156 -0
  151. package/src/stations/useGenerateSceneRowJobs.ts +282 -0
  152. package/src/style/app.css +4974 -0
  153. package/src/transport/client.ts +262 -0
  154. package/src/transport/telemetry.ts +97 -0
  155. package/src/video/DropReceptacle.tsx +122 -0
  156. package/src/video/PromptAssistButtons.tsx +118 -0
  157. package/src/video/composerBridge.ts +66 -0
  158. package/src/video/contract.ts +599 -0
  159. package/src/video/jobTracker.ts +702 -0
  160. package/src/video/mediaLibrary.ts +328 -0
  161. package/src/video/renderCompat.ts +512 -0
  162. package/src/video/sessionForm.ts +189 -0
  163. package/src/video/spreadAssist.ts +392 -0
  164. package/src/video/studioBridge.ts +82 -0
  165. package/src/video/useMediaJobs.ts +279 -0
  166. package/src/video/useModels.ts +413 -0
  167. package/src/video/useMoviePresets.ts +97 -0
  168. package/src/video/useMovieSessions.ts +292 -0
  169. package/src/video/usePresets.ts +167 -0
  170. package/src/video/useProjects.ts +87 -0
  171. package/src/video/usePromptAssist.ts +394 -0
  172. package/src/video/useRenderPresets.ts +221 -0
  173. package/src/video/useStudioAssistLog.ts +266 -0
  174. package/src/video/useStudioPresets.ts +128 -0
  175. package/src/video/useWorkerCalls.ts +165 -0
  176. package/tsconfig.json +17 -0
  177. package/vite.config.ts +33 -0
@@ -0,0 +1,220 @@
1
+ // STUDIO-ASSIST LIVE LOG PANEL (operator directive, 2026-07-31).
2
+ //
3
+ // "a live log in the studio ui showing what each generate attempt actually
4
+ // returned — the raw model reply, what was stripped, and the outcome — so they
5
+ // can self-diagnose without asking the keeper each time."
6
+ //
7
+ // One row per generate attempt, newest first. Each row shows time, the model
8
+ // asked-for → the one that answered, the mode/kind, an outcome badge, and the
9
+ // elapsed time. The RAW model reply is the money view — collapsed by default,
10
+ // expanded on click — alongside the think-stripped `text`, the `reasoning` that
11
+ // was pulled out, and a "from reasoning" mark when the answer was salvaged from
12
+ // the monologue (the "returned only reasoning and no output" case). A parse
13
+ // failure ("did not return the JSON object the spread contract requires") shows
14
+ // the same raw reply so the operator sees exactly what the model sent.
15
+ //
16
+ // Presentation only: it reads the shared stream hook and holds no editor state.
17
+ // Styling lives in style/app.css under the vi-assistlog-* classes (the arm's
18
+ // convention — components carry no styling logic).
19
+ import { useMemo, useState } from "react";
20
+ import { useStudioAssistLog, type AssistAttempt } from "../../video/useStudioAssistLog";
21
+
22
+ const OUTCOME_LABEL: Record<string, string> = {
23
+ served: "served",
24
+ empty: "empty",
25
+ parse_error: "parse error",
26
+ worker_error: "worker error",
27
+ resolve_error: "resolve error",
28
+ };
29
+
30
+ function outcomeClass(outcome?: string): string {
31
+ switch (outcome) {
32
+ case "served":
33
+ return "vi-assistlog-badge vi-assistlog-badge--ok";
34
+ case "empty":
35
+ case "parse_error":
36
+ return "vi-assistlog-badge vi-assistlog-badge--warn";
37
+ case "worker_error":
38
+ case "resolve_error":
39
+ return "vi-assistlog-badge vi-assistlog-badge--err";
40
+ default:
41
+ return "vi-assistlog-badge";
42
+ }
43
+ }
44
+
45
+ function fmtClock(ts?: number): string {
46
+ if (!ts) return "";
47
+ try {
48
+ return new Date(ts * 1000).toLocaleTimeString();
49
+ } catch {
50
+ return "";
51
+ }
52
+ }
53
+
54
+ function fmtMs(ms?: number): string {
55
+ if (ms == null) return "";
56
+ if (ms < 1000) return `${Math.round(ms)} ms`;
57
+ return `${(ms / 1000).toFixed(1)}s`;
58
+ }
59
+
60
+ function AttemptRow({ rec }: { rec: AssistAttempt }) {
61
+ const [open, setOpen] = useState(false);
62
+ const model =
63
+ rec.model_resolved && rec.model_resolved !== rec.model_requested
64
+ ? `${rec.model_requested ?? "?"} → ${rec.model_resolved}`
65
+ : rec.model_requested ?? rec.model_resolved ?? "?";
66
+ const modeKind = [rec.mode, rec.kind].filter(Boolean).join(" · ");
67
+ const hasDetail = Boolean(rec.raw || rec.text || rec.reasoning || rec.error);
68
+
69
+ return (
70
+ <div className={`vi-assistlog-row vi-assistlog-row--${rec.outcome ?? "unknown"}`}>
71
+ <button
72
+ type="button"
73
+ className="vi-assistlog-head"
74
+ onClick={() => hasDetail && setOpen((o) => !o)}
75
+ aria-expanded={open}
76
+ title={hasDetail ? "Show the raw model reply" : undefined}
77
+ >
78
+ <span className="vi-assistlog-caret">{hasDetail ? (open ? "▾" : "▸") : "·"}</span>
79
+ <span className="vi-assistlog-time">{fmtClock(rec.ts)}</span>
80
+ <span className="vi-assistlog-model" title={model}>
81
+ {model}
82
+ </span>
83
+ {modeKind && <span className="vi-assistlog-mode">{modeKind}</span>}
84
+ {rec.from_reasoning && (
85
+ <span
86
+ className="vi-assistlog-chip"
87
+ title="No prose came back — the prompt was salvaged from the model's reasoning"
88
+ >
89
+ from reasoning
90
+ </span>
91
+ )}
92
+ <span className="vi-assistlog-spacer" />
93
+ {rec.elapsed_ms != null && <span className="vi-assistlog-elapsed">{fmtMs(rec.elapsed_ms)}</span>}
94
+ <span className={outcomeClass(rec.outcome)}>
95
+ {OUTCOME_LABEL[rec.outcome ?? ""] ?? rec.outcome ?? "?"}
96
+ </span>
97
+ </button>
98
+
99
+ {rec.error && !open && <div className="vi-assistlog-errline">{rec.error}</div>}
100
+
101
+ {open && (
102
+ <div className="vi-assistlog-detail">
103
+ {rec.error && (
104
+ <div className="vi-assistlog-field">
105
+ <span className="vi-assistlog-label">error</span>
106
+ <div className="vi-assistlog-errbox">{rec.error}</div>
107
+ </div>
108
+ )}
109
+ <div className="vi-assistlog-field">
110
+ <span className="vi-assistlog-label">
111
+ raw reply{rec.raw_truncated ? " (truncated)" : ""}
112
+ </span>
113
+ <pre className="vi-assistlog-raw">
114
+ {rec.raw != null && rec.raw !== "" ? rec.raw : <em>(no reply came back)</em>}
115
+ </pre>
116
+ </div>
117
+ {rec.text && (
118
+ <div className="vi-assistlog-field">
119
+ <span className="vi-assistlog-label">stripped text (the prompt)</span>
120
+ <pre className="vi-assistlog-text">{rec.text}</pre>
121
+ </div>
122
+ )}
123
+ {rec.reasoning && (
124
+ <div className="vi-assistlog-field">
125
+ <span className="vi-assistlog-label">reasoning (stripped out)</span>
126
+ <pre className="vi-assistlog-reasoning">{rec.reasoning}</pre>
127
+ </div>
128
+ )}
129
+ </div>
130
+ )}
131
+ </div>
132
+ );
133
+ }
134
+
135
+ export function StudioAssistLogPanel() {
136
+ const { attempts, conn, error, reconnect } = useStudioAssistLog();
137
+ const [filter, setFilter] = useState("");
138
+ const [collapsed, setCollapsed] = useState(false);
139
+
140
+ const rows = useMemo(() => {
141
+ const q = filter.trim().toLowerCase();
142
+ const out: AssistAttempt[] = [];
143
+ for (let i = attempts.length - 1; i >= 0; i--) {
144
+ const r = attempts[i];
145
+ if (!q) {
146
+ out.push(r);
147
+ continue;
148
+ }
149
+ const hay = [
150
+ r.mode,
151
+ r.kind,
152
+ r.outcome,
153
+ r.model_requested,
154
+ r.model_resolved,
155
+ r.error,
156
+ r.raw,
157
+ ]
158
+ .filter(Boolean)
159
+ .join(" ")
160
+ .toLowerCase();
161
+ if (hay.includes(q)) out.push(r);
162
+ }
163
+ return out;
164
+ }, [attempts, filter]);
165
+
166
+ return (
167
+ <section className="vi-assistlog">
168
+ <header className="vi-assistlog-toolbar">
169
+ <button
170
+ type="button"
171
+ className="vi-assistlog-collapse"
172
+ onClick={() => setCollapsed((c) => !c)}
173
+ aria-expanded={!collapsed}
174
+ >
175
+ {collapsed ? "▸" : "▾"} Generation log
176
+ </button>
177
+ <span className={`vi-assistlog-dot vi-assistlog-dot--${conn}`} title={`stream ${conn}`} />
178
+ <span className="vi-assistlog-conn">{conn}</span>
179
+ <span className="vi-assistlog-spacer" />
180
+ {!collapsed && (
181
+ <input
182
+ className="vi-assistlog-filter"
183
+ value={filter}
184
+ placeholder="filter by model, mode, outcome…"
185
+ onChange={(e) => setFilter(e.target.value)}
186
+ />
187
+ )}
188
+ {conn === "disconnected" && (
189
+ <button type="button" className="vi-assistlog-reconnect" onClick={reconnect}>
190
+ Reconnect
191
+ </button>
192
+ )}
193
+ <span className="vi-assistlog-count">
194
+ {rows.length} attempt{rows.length === 1 ? "" : "s"}
195
+ </span>
196
+ </header>
197
+
198
+ {!collapsed && (
199
+ <>
200
+ {error && <div className="vi-assistlog-error">{error}</div>}
201
+ {rows.length === 0 ? (
202
+ <div className="vi-assistlog-empty">
203
+ No generation attempts recorded yet. Each Enhance / Generate / Spread /
204
+ Negative call lands here — the raw model reply, what was stripped, and the
205
+ outcome.
206
+ </div>
207
+ ) : (
208
+ <div className="vi-assistlog-list">
209
+ {rows.map((r) => (
210
+ <AttemptRow key={r.run_id ?? r._id ?? `${r.ts}-${r.seq}`} rec={r} />
211
+ ))}
212
+ </div>
213
+ )}
214
+ </>
215
+ )}
216
+ </section>
217
+ );
218
+ }
219
+
220
+ export default StudioAssistLogPanel;
@@ -0,0 +1,29 @@
1
+ // The Generate station's "studio" MODE — the in-flow entry point for the fourth tier
2
+ // of the image | scene | movie | studio chain. It mounts the SHARED StudioPlane (the
3
+ // SAME single plane the standalone Studio station renders): generate controls on top,
4
+ // clip viewer + list inline below. A studio job enqueued here is byte-identical to one
5
+ // enqueued from the standalone station, and it appears in the plane's inline list +
6
+ // viewer without leaving the Generate flow.
7
+ //
8
+ // This mode does NOT register the studioBridge (registerBridge defaults false): the
9
+ // sidebar's "Send to Studio" navigates to the standalone /studio-clips station, which
10
+ // owns the registration. The plane is wrapped in the same stacked work-region the other
11
+ // Generate modes render into (the classes SectionTabs emits for a no-options work
12
+ // column), so switching image → scene → movie → studio reads as one continuous flow.
13
+ import { StudioPlane } from "./StudioPlane";
14
+
15
+ export interface StudioGenerateModeProps {
16
+ /** Set by the top-level Generate tab (Clip → "clip", Cinema → "movie") to lock the
17
+ * studio surface to one sub-mode and hide its internal Clip|Cinema switcher. */
18
+ lockedSurfaceMode?: "clip" | "movie";
19
+ }
20
+
21
+ export function StudioGenerateMode({ lockedSurfaceMode }: StudioGenerateModeProps = {}) {
22
+ return (
23
+ <div className="vi-section-tabs vi-section-tabs--stacked">
24
+ <section className="vi-section-region vi-section-region--work" aria-label="Studio">
25
+ <StudioPlane lockedSurfaceMode={lockedSurfaceMode} />
26
+ </section>
27
+ </div>
28
+ );
29
+ }