@hypit/hypit 0.1.3 → 0.1.4
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/dist/public/studio-adapter.d.ts +31 -2
- package/package.json +4 -1
- package/packages/audio-track-studio/src/index.ts +7 -4
- package/packages/build-result/README.md +58 -0
- package/packages/build-result/package.json +2 -1
- package/packages/build-result/src/decode.ts +10 -8
- package/packages/build-result/src/file-reference.ts +42 -0
- package/packages/build-result/src/index.ts +3 -0
- package/packages/build-result/src/replace-file-windows.ts +58 -0
- package/packages/build-result/src/replace-file.ts +11 -0
- package/packages/build-result/src/store.ts +44 -13
- package/packages/build-result/src/types.ts +38 -8
- package/packages/build-result/src/writer.ts +12 -1
- package/packages/build-result-fs/README.md +23 -1
- package/packages/build-result-s3/README.md +5 -0
- package/packages/build-result-s3/src/repository.ts +19 -5
- package/packages/caption-fine/README.md +17 -2
- package/packages/caption-fine/src/manifest.ts +1 -1
- package/packages/caption-fine/src/render.ts +48 -36
- package/packages/caption-fine-studio/package.json +8 -3
- package/packages/caption-fine-studio/src/index.ts +10 -1
- package/packages/cli/README.md +25 -0
- package/packages/cli/src/arguments.ts +16 -11
- package/packages/cli/src/build-planning.ts +6 -1
- package/packages/cli/src/command.ts +1 -1
- package/packages/cli/src/commands/environment.ts +42 -13
- package/packages/cli/src/machine-view.ts +12 -3
- package/packages/cli/src/main.ts +4 -0
- package/packages/cli/src/output.ts +28 -12
- package/packages/cli/src/result-export.ts +22 -13
- package/packages/cli/src/run-file.ts +19 -8
- package/packages/comment-sticker-studio/src/index.ts +2 -1
- package/packages/compiler-node/src/compiler.ts +1 -0
- package/packages/estimate/README.md +56 -3
- package/packages/estimate/src/program.ts +7 -8
- package/packages/fonts-open/README.md +5 -0
- package/packages/fonts-open/package.json +5 -1
- package/packages/fonts-open/src/studio.ts +21 -0
- package/packages/media-track-studio/src/index.ts +7 -2
- package/packages/provider-whisperx-local/README.md +57 -0
- package/packages/ranking/src/render.ts +11 -9
- package/packages/ranking-studio/README.md +11 -0
- package/packages/ranking-studio/package.json +8 -3
- package/packages/ranking-studio/src/index.ts +11 -4
- package/packages/runtime/src/catalog.ts +2 -0
- package/packages/runtime-host-node/src/index.ts +1 -0
- package/packages/runtime-local/README.md +19 -0
- package/packages/runtime-local/src/programs.ts +39 -24
- package/packages/runtime-local/src/runtime.ts +2 -0
- package/packages/script/README.md +22 -0
- package/packages/script/src/edit.ts +123 -73
- package/packages/script/src/lexical.ts +40 -6
- package/packages/script/src/parser.ts +36 -8
- package/packages/script/src/types.ts +4 -0
- package/packages/seedance-kits/README.md +3 -1
- package/packages/seedance-kits/kits/speaker-v1.svs +5 -5
- package/packages/speech-alignment/src/align.ts +45 -21
- package/packages/studio/INSPECTOR.md +104 -0
- package/packages/studio/README.md +65 -4
- package/packages/studio/src/build-library.ts +99 -84
- package/packages/studio/src/library-media.ts +19 -0
- package/packages/studio/src/parameter-values.ts +41 -1
- package/packages/studio/src/parameters.ts +20 -21
- package/packages/studio/src/server.ts +58 -30
- package/packages/studio/src/shared.ts +20 -6
- package/packages/studio/src/studio-registry.ts +22 -0
- package/packages/studio/src/style.css +135 -144
- package/packages/studio/src/temporal-edit.ts +131 -0
- package/packages/studio/src/ui/artifact-name.ts +80 -0
- package/packages/studio/src/ui/artifact-preview.ts +99 -0
- package/packages/studio/src/ui/icons.ts +5 -1
- package/packages/studio/src/ui/library.ts +373 -192
- package/packages/studio/src/ui/main.ts +153 -31
- package/packages/studio/src/ui/material-preview.ts +1 -1
- package/packages/studio/src/ui/overlay.ts +21 -20
- package/packages/studio/src/ui/sidebar-panel.ts +31 -0
- package/packages/studio/src/ui/stage.ts +124 -8
- package/packages/studio/src/ui/timeline.ts +16 -179
- package/packages/studio/start.ts +15 -3
- package/packages/studio-adapter/README.md +21 -0
- package/packages/studio-adapter/src/index.ts +26 -1
- package/packages/temporal-markup/EDITING.md +183 -0
- package/packages/temporal-markup/README.md +4 -0
- package/packages/typography-track-studio/package.json +8 -3
- package/packages/typography-track-studio/src/index.ts +5 -1
- package/packages/video-cli/README.md +12 -3
- package/packages/video-cli/src/creation.ts +11 -5
- package/packages/whisperx/README.md +7 -0
- package/packages/workspace/src/index.ts +2 -0
- package/packages/workspace-fs-node/README.md +4 -1
- package/packages/workspace-fs-node/src/workspace.ts +3 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Author-directed time editing
|
|
2
|
+
|
|
3
|
+
The shared temporal author forms declare what Studio can edit. The tables below describe their
|
|
4
|
+
implemented behavior; a component's Companion also supplies the actual Source bindings.
|
|
5
|
+
The runtime projection types remain `@1`.
|
|
6
|
+
|
|
7
|
+
## Relationships, expressions, and resolved time
|
|
8
|
+
|
|
9
|
+
Selection and Moment name relationships in a Narrative. A Selection names two anchors; a Moment
|
|
10
|
+
names one. Neither carries a duration measured in seconds. Segment and Program boundaries retain
|
|
11
|
+
their structural meaning alongside word boundaries.
|
|
12
|
+
|
|
13
|
+
A temporal expression describes how to obtain time from those relationships or from a clock.
|
|
14
|
+
Projection resolves that description in a ProgramSpace. Its products are TemporalInstant and
|
|
15
|
+
TemporalWindow, which a component consumes to implement its own schedule and appearance.
|
|
16
|
+
|
|
17
|
+
In temporal author attributes, `{story.moment.reveal}` is a direct typed reference. Quoted values
|
|
18
|
+
such as `"2s"` and `"moment.cue + 2f"` are clock descriptions. Quotation marks do not themselves
|
|
19
|
+
produce an Instant or Window, and braces elsewhere in SVML can reference any public value type.
|
|
20
|
+
Both semantic references and clock descriptions reach consumers through temporal projection.
|
|
21
|
+
The consumer's role determines whether one Instant or a Window is needed.
|
|
22
|
+
|
|
23
|
+
The editing rule is: **edit the relationship or parameter the author exposed, preserving the
|
|
24
|
+
relationship they chose to depend on.** Knowing where a result came from does not by itself grant
|
|
25
|
+
an inverse that changes that source.
|
|
26
|
+
|
|
27
|
+
## Direct bindings
|
|
28
|
+
|
|
29
|
+
| Author form | Move | Leading edge | Trailing edge |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| `during={story.selection.proof}` | Move both Selection anchors by the same number of semantic stops; duration may change. | Change its start anchor. | Change its end anchor. |
|
|
32
|
+
| `at={story.moment.reveal}` for an Instant | Change the Moment anchor. | Not applicable. | Not applicable. |
|
|
33
|
+
| `at={story.selection.proof} boundary="start"` for an Instant | Change only the Selection start anchor. | Not applicable. | Not applicable. |
|
|
34
|
+
| `at={story.selection.proof} boundary="end"` for an Instant | Change only the Selection end anchor. | Not applicable. | Not applicable. |
|
|
35
|
+
| `during={story.segment.opening}` or `during="program"` | Follow the structural span; no timeline write. | No timeline write. | No timeline write. |
|
|
36
|
+
| A directly selected Segment boundary | Follow that structural boundary; no timeline write. | Not applicable. | Not applicable. |
|
|
37
|
+
|
|
38
|
+
A shared Selection or Moment is edited once in Script. All its consumers follow after compilation.
|
|
39
|
+
An item's placement in a track does not make its own private copy of that relationship.
|
|
40
|
+
|
|
41
|
+
Word starts, word ends, Segment starts, and Segment ends are equally eligible semantic anchors.
|
|
42
|
+
Selection starts do not inherently prefer word starts; Selection ends do not inherently prefer
|
|
43
|
+
word ends. Endpoints can include pauses by referring to the appropriate neighboring anchor.
|
|
44
|
+
|
|
45
|
+
## An event and a duration
|
|
46
|
+
|
|
47
|
+
These forms expose two independent decisions: an event or clock position, and a duration.
|
|
48
|
+
|
|
49
|
+
| Author form | Move | Leading edge | Trailing edge |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| `at={story.moment.reveal} for="8f"` | Change the Moment; keep `for`. | No handle. | Change `for`; keep the Moment. |
|
|
52
|
+
| `until={story.moment.reveal} for="8f"` | Change the Moment; keep `for`. | Change `for`; keep the Moment. | No handle. |
|
|
53
|
+
| `at="2s" for="8f"` | Change `at`; keep `for`. | No handle. | Change `for`; keep `at`. |
|
|
54
|
+
| `until="2s" for="8f"` | Change `until`; keep `for`. | Change `for`; keep `until`. | No handle. |
|
|
55
|
+
|
|
56
|
+
Moving an event-and-duration window preserves duration. Moving a direct Selection window preserves
|
|
57
|
+
semantic step displacement instead. These are different author decisions, so they have different
|
|
58
|
+
behavior even when their current rectangles look identical.
|
|
59
|
+
|
|
60
|
+
The unavailable edge does not secretly edit both the event and the duration. Duration editing is
|
|
61
|
+
frame-based; semantic event editing selects an anchor. There is no `at` plus `until` Window form:
|
|
62
|
+
current forms are `during`, `at/for`, `until/for`, and `start/end`.
|
|
63
|
+
|
|
64
|
+
## Clock positions and explicit offsets
|
|
65
|
+
|
|
66
|
+
A literal Instant such as `at="2s"` exposes one numeric time and can move by rewriting that value.
|
|
67
|
+
A reference expression exposes a local offset while retaining its referenced event:
|
|
68
|
+
|
|
69
|
+
```svml
|
|
70
|
+
moment={story.moment.reveal}
|
|
71
|
+
instant="moment.cue + 2f"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Moving this Instant changes the signed offset only. It does not relocate the Moment in Script.
|
|
75
|
+
The same rule applies to an explicit offset from a selected boundary or a Program boundary.
|
|
76
|
+
The expression's reference remains unchanged through the write.
|
|
77
|
+
|
|
78
|
+
A bare reference expression such as `instant="moment.cue"` has an implicit zero offset. Moving it
|
|
79
|
+
writes an offset such as `moment.cue+3f`; it leaves the Moment in Script unchanged. The direct
|
|
80
|
+
binding `at={...}` is the form that edits the Moment itself.
|
|
81
|
+
|
|
82
|
+
Bare references and explicit `+0f` have the same editing behavior. Writeback uses an explicit frame
|
|
83
|
+
offset, including at zero. Positive, zero, and negative offsets belong to the same editing operation,
|
|
84
|
+
subject to the resulting projection being usable.
|
|
85
|
+
|
|
86
|
+
The existing syntax uses `instant` for expressions and a separate typed `moment`, `selection`, or
|
|
87
|
+
`segment` attribute to bind their source. This design does not add an implicit name resolver or
|
|
88
|
+
put arithmetic inside `{...}`. Unifying surface attribute spellings is a separate usability choice,
|
|
89
|
+
not a prerequisite for establishing these edit semantics.
|
|
90
|
+
|
|
91
|
+
## Independently authored endpoints
|
|
92
|
+
|
|
93
|
+
`start="..." end="..."` expresses a deliberately assembled Window. Its expressions may use different
|
|
94
|
+
sources, boundaries, absolute times, and offsets. This form remains available for production,
|
|
95
|
+
including pure motion graphics and windows extending around a spoken passage.
|
|
96
|
+
|
|
97
|
+
Each endpoint is edited exactly like an Instant expression: a literal changes its absolute time;
|
|
98
|
+
a reference changes its local offset. A leading trim changes `start`, a trailing trim changes `end`,
|
|
99
|
+
and a whole-window move shifts both endpoints by the same frame delta. Each expression retains its
|
|
100
|
+
own reference, even when the endpoints depend on different sources. The referenced Script markers
|
|
101
|
+
remain unchanged. Companion bindings identify the two writable source parameters.
|
|
102
|
+
|
|
103
|
+
## Seconds and frames
|
|
104
|
+
|
|
105
|
+
Seconds and milliseconds describe clock duration; frames describe steps at the ProgramSpace's
|
|
106
|
+
frame rate. `2s` remains two seconds when the rate changes, whereas `60f` spans two seconds at 30fps
|
|
107
|
+
and one second at 60fps. Parsing retains that authored unit. Projection uses exact rational arithmetic
|
|
108
|
+
and rounds the resulting position to the nearest frame boundary, with half-frame ties rounding later.
|
|
109
|
+
|
|
110
|
+
Timeline gestures operate on whole frames in the current ProgramSpace. A changed absolute value is
|
|
111
|
+
written in frames, and a changed reference expression receives a frame offset. Unedited expressions
|
|
112
|
+
retain their spelling and units. This makes a drag's result exact at the current frame rate without
|
|
113
|
+
silently converting all authored clock durations into frame counts.
|
|
114
|
+
|
|
115
|
+
## Semantic stops and coincident anchors
|
|
116
|
+
|
|
117
|
+
Script order, anchor identity, and projected frame position are separate data:
|
|
118
|
+
|
|
119
|
+
- Script order determines which inline Selection an author surface can express.
|
|
120
|
+
- Projected frame position determines where an event appears in the current performance.
|
|
121
|
+
- Anchor identity determines which relationship survives later changes to that performance.
|
|
122
|
+
|
|
123
|
+
Build the gesture's semantic stops from distinct projected frame positions in chronological order.
|
|
124
|
+
Several anchors at one frame occupy one stop but retain their individual identities. A direct
|
|
125
|
+
Selection move advances both endpoints by the same signed number of stops. It does not shift a raw
|
|
126
|
+
anchor-array index, assume one stop is one word, or preserve a duration measured in frames.
|
|
127
|
+
|
|
128
|
+
Ties first retain the current anchor where it is still a candidate, then prefer its kind, then use
|
|
129
|
+
a stable declared order. This is a default choice among coincident candidates, not a hierarchy of
|
|
130
|
+
valid anchors. Selecting a semantic marker shows its exact anchors in the Inspector. Where declared
|
|
131
|
+
handles allow it, a choice lists the other anchors at the same frame; horizontal mouse position alone
|
|
132
|
+
cannot distinguish them. That explicit choice uses the same Script adjustment operation as dragging.
|
|
133
|
+
|
|
134
|
+
Segment overlap or gaps can change temporal order without changing Script order. Stop construction
|
|
135
|
+
must not assume contiguous Segments. The current SemanticTrack implementation still concatenates
|
|
136
|
+
Take durations; introducing explicit Take placement is separate work.
|
|
137
|
+
|
|
138
|
+
## Selection, projection, and consumption
|
|
139
|
+
|
|
140
|
+
A Selection that is forward in Script may locate to equal or reversed frame endpoints. This does
|
|
141
|
+
not alone establish whether every use of that Selection is invalid. A consumer may use only its
|
|
142
|
+
start, or an expression may add offsets before composing a Window.
|
|
143
|
+
|
|
144
|
+
Script validates the relationship it can express. Temporal projection validates the resulting
|
|
145
|
+
Instant or Window in its ProgramSpace. Components validate their own use of those results.
|
|
146
|
+
Studio offers only gestures with a declared inverse and candidate targets that preserve the
|
|
147
|
+
edited object's usable projection. It does not add a global positive-duration rule to Selection.
|
|
148
|
+
|
|
149
|
+
Both endpoints of a range adjustment are written in one operation. Recompilation remains the check
|
|
150
|
+
for effects on other consumers of the shared relationship. An unsuccessful publication leaves the
|
|
151
|
+
previous source and displayed state in place through the existing source transaction; this does not
|
|
152
|
+
introduce a Build recovery workflow or a second mutable source of truth.
|
|
153
|
+
|
|
154
|
+
A hidden or invalid initial object does not need an automatic repair interface. Conversely, a valid
|
|
155
|
+
editable object must not disappear because the editor committed a target its own projection cannot
|
|
156
|
+
represent. The relevant closure is over meaningful relationships and supported operations, not every
|
|
157
|
+
possible raw spelling of the document.
|
|
158
|
+
|
|
159
|
+
## Implementation ownership
|
|
160
|
+
|
|
161
|
+
The existing protocol already distinguishes `TemporalSource` from `TemporalInstantAuthority`.
|
|
162
|
+
Preserve this separation. A source says what time depends on; authority identifies an intentional
|
|
163
|
+
write target. The `fixed` case means no temporal gesture writes that endpoint, not that all author
|
|
164
|
+
parameter editing is forbidden.
|
|
165
|
+
|
|
166
|
+
- `@hypit/script` owns tokenization, anchor identities, legal marker sites, and structural writeback.
|
|
167
|
+
It normalizes equivalent marker whitespace, retains punctuation and attributes, writes coincident
|
|
168
|
+
markers together, and preserves all unrelated relationships and caption information.
|
|
169
|
+
- `@hypit/temporal-markup` owns the interpretation of each time form and declares its write targets.
|
|
170
|
+
Direct semantic references expose semantic targets; quoted time expressions expose parameter
|
|
171
|
+
targets, including implicit zero offsets and independent endpoints. Structural bindings retain
|
|
172
|
+
their structural boundaries without a timeline write target.
|
|
173
|
+
- `@hypit/temporal` resolves time and validates its results. It does not infer a user editing choice
|
|
174
|
+
from invertibility or know Studio's UI.
|
|
175
|
+
- Companion/Studio translates those declared relationships into the finite operations above.
|
|
176
|
+
Existing `after-start` and `before-end` duration relationships already distinguish event-and-duration
|
|
177
|
+
windows. Explicit source bindings remain the write allowlist. Component names and media types
|
|
178
|
+
do not decide which operation is available.
|
|
179
|
+
|
|
180
|
+
Script tests exercise repeated marker moves and return trips across English, Chinese, Dual Text,
|
|
181
|
+
punctuation, token attributes, and empty Segments. Temporal Markup tests check author authority;
|
|
182
|
+
Studio tests check handles, semantic-stop movement, projected validity, and offset writes through zero.
|
|
183
|
+
The same semantic gesture projection is used for the timeline preview and server-side validation.
|
|
@@ -9,6 +9,10 @@ The package exports `createTemporalWindowProjection`, `createTemporalInstantProj
|
|
|
9
9
|
`resolveTemporalContext`, `createTemporalSpace`, attribute vocabulary, and the exact duration/instant parsers. These are helpers for component
|
|
10
10
|
Surfaces, not standalone author tags or a new Track.
|
|
11
11
|
|
|
12
|
+
The editing behavior is specified in [Author-directed time editing](EDITING.md).
|
|
13
|
+
It separates direct bindings, durations, and explicit offsets from derived results, with a precise
|
|
14
|
+
write target for each supported gesture.
|
|
15
|
+
|
|
12
16
|
## Time context
|
|
13
17
|
|
|
14
18
|
A Track Surface can accept `semantic={speech.semantic}` or `space={animation}`. Resolve that choice
|
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
7
|
-
"exports": {
|
|
8
|
-
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"hypit": {
|
|
11
|
+
"activation": "./src/activation.ts"
|
|
12
|
+
},
|
|
9
13
|
"dependencies": {
|
|
10
14
|
"@hypit/composition": "workspace:*",
|
|
11
15
|
"@hypit/studio-adapter": "workspace:*",
|
|
12
|
-
"@hypit/typography-track": "workspace:*"
|
|
16
|
+
"@hypit/typography-track": "workspace:*",
|
|
17
|
+
"@hypit/fonts-open": "workspace:*"
|
|
13
18
|
}
|
|
14
19
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { openFontStudioFields } from "@hypit/fonts-open/studio";
|
|
1
2
|
import { typographyTrackMarkupSurfaces, typographyTrackModuleRef, typographyTrackTypes } from "@hypit/typography-track";
|
|
2
3
|
import type { TypographyTrackProgram } from "@hypit/typography-track";
|
|
3
4
|
import { compositionTypes } from "@hypit/composition";
|
|
4
5
|
import type { StudioTrackCompanion, StudioTrackCompanionContext, StudioEntityDraft, StudioInspectorFieldDeclaration } from "@hypit/studio-adapter";
|
|
5
6
|
import { childEntities, requiredSurfaceValue, temporalLineageFor, temporalSemanticSource, textLayer } from "@hypit/studio-adapter";
|
|
6
7
|
|
|
8
|
+
const fontInspector = openFontStudioFields("style");
|
|
9
|
+
|
|
7
10
|
const typographyProperties = (typographyTrackMarkupSurfaces
|
|
8
11
|
.find((surface) => surface.name === "style")?.vocabulary.attributes
|
|
9
12
|
.find((attribute) => attribute.name === "recipe")?.recipe ?? []);
|
|
@@ -105,11 +108,12 @@ export const typographyTrackStudioTrackCompanions: readonly StudioTrackCompanion
|
|
|
105
108
|
{ name: "content" },
|
|
106
109
|
{
|
|
107
110
|
name: "style",
|
|
111
|
+
referenced: [fontInspector.binding],
|
|
108
112
|
recipe: { through: ["recipe"], bindings: typographyProperties.map(({ name }) => ({ name })) },
|
|
109
113
|
},
|
|
110
114
|
{ name: "motion" },
|
|
111
115
|
],
|
|
112
|
-
inspector: typographyInspector,
|
|
116
|
+
inspector: [...fontInspector.fields, ...typographyInspector],
|
|
113
117
|
requiredValues: ["program"], project: projectTypography,
|
|
114
118
|
lane: { heightPx: 48 },
|
|
115
119
|
},
|
|
@@ -37,14 +37,23 @@ Result or state. It names the Endpoint and its price page before it runs, and wr
|
|
|
37
37
|
to the chosen file. `measure` estimates a passage locally:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
hypit transcribe reference.mp4 --to notes/reference.transcript.json
|
|
40
|
+
hypit transcribe reference.mp4 --to notes/reference.transcript.json --language en
|
|
41
41
|
hypit measure main.svml --segment hook --language en --pace normal --rounding round
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
For `transcribe`, set `--language` to the spoken language: `en`, `zh` or `es`. Chinese speech uses `zh`, including
|
|
45
|
+
Chinese speech containing English names; the requested language selects the recognition/alignment
|
|
46
|
+
model, independently of the eventual caption font or script's simplified/traditional characters.
|
|
47
|
+
|
|
44
48
|
`transcribe` uses the Profile's `whisperx-alignment` Endpoint (after
|
|
45
49
|
extracting 16 kHz mono speech audio with ffmpeg). `measure` counts a Segment's pronunciation units at a
|
|
46
|
-
delivery policy and prints
|
|
47
|
-
|
|
50
|
+
delivery policy and prints estimated seconds, the resolved rate, padding and rounding. Choose the
|
|
51
|
+
literal `duration` from that estimate and the intended performance. `measure` opens no Profile and
|
|
52
|
+
spends nothing. It accepts `--pace slow|normal|fast` or `--rate <units/s>`; JSON includes the resolved
|
|
53
|
+
`rate` even when using a named pace. [Estimate](../estimate/README.md#units-and-delivery) explains
|
|
54
|
+
Chinese/English units and choosing a whole-passage density.
|
|
55
|
+
|
|
56
|
+
For `transcribe`, `--runtime <profile>` names the Profile; otherwise the project's `hypit runtime use`
|
|
48
57
|
selection is read. Anything the Author Graph declares as an output is a Build, however quickly it
|
|
49
58
|
comes back: pictures, clips and accepted voice references (`@hypit/mimo-speech`) carry the identity of the Source
|
|
50
59
|
that produced them, so they are declared in the Source and go through `plan` and `build`. To hear a
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
countSpeechEstimateUnits,
|
|
10
10
|
estimateSpeechDuration,
|
|
11
11
|
resolveSpeechEstimateLanguage,
|
|
12
|
+
resolveSpeechEstimateRate,
|
|
12
13
|
speechEstimatePolicyFromAttributes,
|
|
13
14
|
} from "@hypit/estimate";
|
|
14
15
|
import type { CanonicalValue, CapabilityRef, Need, StoredValue } from "@hypit/protocol";
|
|
@@ -275,8 +276,9 @@ async function transcribe(argv: readonly string[], io: CliIo, environment: Creat
|
|
|
275
276
|
const parsed = parseArguments(argv, ["--language", "--to", "--runtime", "--workspace"]);
|
|
276
277
|
assert(parsed.positionals.length === 1, "transcribe takes exactly one audio or video file");
|
|
277
278
|
const source = resolve(environment.cwd, parsed.positionals[0]!);
|
|
278
|
-
const language = parsed.options.get("--language")
|
|
279
|
-
assert(language === "en" || language === "zh" || language === "es",
|
|
279
|
+
const language = parsed.options.get("--language");
|
|
280
|
+
assert(language === "en" || language === "zh" || language === "es",
|
|
281
|
+
"transcribe requires --language en|zh|es for the spoken language (use --language zh for Chinese)");
|
|
280
282
|
const to = await destination(parsed, environment.cwd);
|
|
281
283
|
const { profile, host } = await environment.openHost(
|
|
282
284
|
parsed.options.get("--runtime"),
|
|
@@ -382,6 +384,7 @@ async function measure(argv: readonly string[], io: CliIo, environment: Creation
|
|
|
382
384
|
}
|
|
383
385
|
const pace = parsed.options.get("--pace");
|
|
384
386
|
const rate = parsed.options.get("--rate");
|
|
387
|
+
assert(pace === undefined || rate === undefined, "measure takes either --pace or --rate, not both");
|
|
385
388
|
const policy = speechEstimatePolicyFromAttributes({
|
|
386
389
|
language: parsed.options.get("--language") ?? "auto",
|
|
387
390
|
...(rate === undefined ? { pace: pace ?? "normal" } : { rate }),
|
|
@@ -391,6 +394,7 @@ async function measure(argv: readonly string[], io: CliIo, environment: Creation
|
|
|
391
394
|
const language = resolveSpeechEstimateLanguage(text, policy.language);
|
|
392
395
|
const units = countSpeechEstimateUnits(text, language);
|
|
393
396
|
const seconds = estimateSpeechDuration(sealText(text), policy);
|
|
397
|
+
const resolvedRate = resolveSpeechEstimateRate(policy, language);
|
|
394
398
|
const view = {
|
|
395
399
|
format: "hypit.video-cli-measure@1",
|
|
396
400
|
...where,
|
|
@@ -398,11 +402,13 @@ async function measure(argv: readonly string[], io: CliIo, environment: Creation
|
|
|
398
402
|
units,
|
|
399
403
|
language,
|
|
400
404
|
policy,
|
|
405
|
+
rate: resolvedRate,
|
|
401
406
|
seconds,
|
|
402
407
|
};
|
|
403
408
|
if (parsed.json) { io.write(`${JSON.stringify(view, null, 2)}\n`); return; }
|
|
404
|
-
const delivery = policy.
|
|
405
|
-
io.write(`${seconds}s\n\n ${units} pronunciation units · ${language} · ${delivery}
|
|
409
|
+
const delivery = `${resolvedRate} units/s${policy.pace === undefined ? "" : ` (${policy.pace})`}`;
|
|
410
|
+
io.write(`${Number(seconds.toFixed(3))}s\n\n ${units} pronunciation units · ${language} · ${delivery}\n`
|
|
411
|
+
+ ` padding ${policy.paddingSec ?? 0}s · rounding ${policy.rounding}\n`
|
|
406
412
|
+ ` ${"segment" in where ? `${where.segment} in ${where.source}` : `${text.length} characters`}\n`
|
|
407
413
|
+ " Choose the request duration from this estimate, the intended performance, and the selected model's supported values.\n");
|
|
408
414
|
}
|
|
@@ -416,7 +422,7 @@ export function writeCreationHelp(io: CliIo, topic?: CreationCommand): void {
|
|
|
416
422
|
"hypit transcribe",
|
|
417
423
|
"Establish word times with the whisperx-alignment Endpoint of the selected Runtime Profile.",
|
|
418
424
|
"",
|
|
419
|
-
" hypit transcribe <audio|video> --to <transcript.json>
|
|
425
|
+
" hypit transcribe <audio|video> --to <transcript.json> --language en|zh|es [--runtime <profile>] [--workspace <project>]",
|
|
420
426
|
"",
|
|
421
427
|
"Extracts 16 kHz mono speech audio with ffmpeg and writes every word with its start and end in",
|
|
422
428
|
"seconds. One immediate request; no Build, Result or state.",
|
|
@@ -17,6 +17,13 @@ projects the Take's audio to canonical 16 kHz mono `SpeechEvidenceAudio`; Whispe
|
|
|
17
17
|
bytes. A deterministic local alignment then combines the returned evidence with the Segment and
|
|
18
18
|
emits one self-contained `SemanticTake`.
|
|
19
19
|
|
|
20
|
+
For Chinese speech, select `zh` (also `hypit transcribe --language zh` for a reference). WhisperX's
|
|
21
|
+
Chinese alignment emits character-sized words, including letters inside some Latin names. The
|
|
22
|
+
evidence adapter preserves those windows; the local alignment maps them onto Script's units, so
|
|
23
|
+
a complete Latin name can consume several evidence words while neighboring Han characters retain
|
|
24
|
+
their own times. Caption gets its displayed wording and Cue breaks from Script, independently of
|
|
25
|
+
the recognizer's punctuation or simplified/traditional spelling.
|
|
26
|
+
|
|
20
27
|
When the authored Segment has no Tokens, write the same Surface without `language`. Its start and
|
|
21
28
|
end Anchors map directly to the prepared media's first and final frame. There are no words to align,
|
|
22
29
|
so this branch requests no evidence audio and no WhisperX capability:
|
|
@@ -9,6 +9,8 @@ import type { BlobRef } from "@hypit/protocol";
|
|
|
9
9
|
/** Repeatably openable transfer bytes admitted by the selected Workspace. */
|
|
10
10
|
export type ArtifactAttachment = {
|
|
11
11
|
readonly artifact: BlobRef;
|
|
12
|
+
/** Stable external address, when the Workspace supplies a file by reference. */
|
|
13
|
+
readonly location?: string;
|
|
12
14
|
open(): Awaitable<AsyncIterable<Uint8Array>>;
|
|
13
15
|
};
|
|
14
16
|
|
|
@@ -4,7 +4,10 @@ Reference Node filesystem implementation of the host-neutral `Workspace` contrac
|
|
|
4
4
|
|
|
5
5
|
Every `open()` call creates one isolated compilation session. It canonicalizes real paths, confines
|
|
6
6
|
local SourceUnit and Source Asset reads to the configured root, rejects symlink escapes, locks each
|
|
7
|
-
edge to the first bytes observed and returns defensive Resource attachments.
|
|
7
|
+
Source edge to the first bytes observed and returns defensive Resource attachments. File attachments
|
|
8
|
+
also carry their resolved `file:` URI so Result publication can preserve the external reference.
|
|
9
|
+
The Resource's identity and metadata belong to the compilation session; its file remains a live
|
|
10
|
+
dependency rather than becoming a persistent snapshot.
|
|
8
11
|
|
|
9
12
|
A Host may supply an external Source resolver. One explicit non-relative Source locator can then
|
|
10
13
|
open a SourceUnit in a separate canonical root; that Source's relative imports and assets remain
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { createReadStream } from "node:fs";
|
|
3
4
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
@@ -177,6 +178,7 @@ class NodeFilesystemWorkspaceSession implements WorkspaceSession {
|
|
|
177
178
|
if (!this.#attachments.has(attachmentKey)) {
|
|
178
179
|
this.#attachments.set(attachmentKey, {
|
|
179
180
|
artifact: { ...artifact },
|
|
181
|
+
location: pathToFileURL(canonical).href,
|
|
180
182
|
open: () => createReadStream(canonical),
|
|
181
183
|
});
|
|
182
184
|
}
|
|
@@ -189,7 +191,7 @@ class NodeFilesystemWorkspaceSession implements WorkspaceSession {
|
|
|
189
191
|
const byResource = left.artifact.resource.localeCompare(right.artifact.resource);
|
|
190
192
|
return byResource === 0 ? left.artifact.mediaType.localeCompare(right.artifact.mediaType) : byResource;
|
|
191
193
|
})
|
|
192
|
-
.map((item) => ({ artifact: { ...item.artifact }
|
|
194
|
+
.map((item) => ({ ...item, artifact: { ...item.artifact } }));
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
|