main_video and audio on main_audio. Send commands with
reactor.sendCommand() once the session reaches ready.
Tracks
There are no input tracks. The model takes everything it needs from commands.
Both tracks stream only while a clip plays. Between clips,
main_video shows black and main_audio
is silent. Turn off set_flush_on_clip_end to hold the last frame instead of black.
Each session starts at 16:9 and the 768p resolution, which is 1344 × 768 pixels. set_resolution
switches between 768p and 480p (832 × 480 at 16:9), and set_canvas changes the aspect ratio.
Call them while both queues are empty and nothing plays, for example before you queue the first
clip. At any other time the size stays fixed. state_update, canvas_accepted, and
resolution_accepted report the size in pixels.
Session lifecycle
A Pika H3 Flex session has two queues:- The generation queue holds clips that wait to generate.
- The playout queue holds clips that are ready to play.
play, unless
autoplay is on.
When you connect, the model sends you a state_update and a queue_update. A new session has both
queues empty, autoplay off, and nothing playing. state_update.valid_commands lists the commands
the session accepts right now. Use it to turn controls on and off in your UI.
Generation keeps going while a clip plays, so you can queue the next clip during playback. It runs
only while at least one client is connected.
Several clients can connect to one session and share its queues and stream. A command from any
client changes the state for all of them. Replies go only to the client that sent the command, while
state, queue, and playback messages go to every client.
reset stops playback, clears both queues and the clips you could continue from, clears the tracks,
and restores the defaults.
Commands
The typed SDK,
@reactor-models/pika-h3-flex, has one method for each command on PikaH3FlexModel
and on the usePikaH3Flex() hook. play and stop resolve undefined. The other methods resolve
their reply message, or undefined if the model refuses the command. Parameter and message fields
keep their snake_case names. Pass the FileRef that uploadFile returns for each uploaded image,
video, or audio clip.
enqueue
Add a clip to the generation queue. The model replies with clip_queued when it accepts the
request. Later it sends clip_generated when the clip is ready, or clip_failed if generation
fails.
The inputs decide how the model builds the clip. There is no field that chooses a mode:
Frame images and references never share a clip. The model refuses a request that combines them with
invalid_request, and it also refuses a frame continuation that has references or frame images.
References
Reference images guide how subjects, objects, and settings look. Reference videos guide motion, appearance, and sound. Reference audio guides voices and sound. None of them fixes the clip’s first or last frame. A clip takes up to 9 images, 3 videos, and 3 audio clips, and at most 12 references in total. A request with reference audio must also include a reference image, a reference video, or a latent continuation, or the model refuses it withinvalid_request. Each clip keeps its own
references, and a later clip does not reuse them.
Upload each file with uploadFile() and pass the FileRef it
returns. The same file uploaded twice counts as two references with two labels.
Labels
In the prompt,<Picture N> names the Nth image and <Video N> the Nth video, in the order of
their own arrays. Audio clips and the sound of reference videos share the <Audio N> numbers, in
packed order. A video with sound takes the next audio label just before its own place. With the
default order, one image, one video with sound, and one audio clip are named like this:
If the video has no sound, the audio clip is
<Audio 1>. If you change reference_order, the
labels change too, so update the prompt to match.
Reference videos
Reference videos are experimental. Each video is 2 to 15 seconds long, at most 64 MiB, and has an aspect ratio between 1:4 and 4:1. The model samples each video at 24 frames per second, cuts it to the clip’s length, and fits it to its own aspect ratio at the session’s resolution. If the video has sound, the sound guides the clip too. The model refuses a video that does not decode or is out of range withinvalid_request.
First and last frames
first_frame_image sets how the clip opens, and last_frame_image sets how it ends. Send one or
both. The model center-crops each image and resizes it to the canvas. It rebuilds the image rather
than pasting it, so the first or last frame is close to the image but not a pixel copy. Describe the
action between the two frames in the prompt. In the prompt, a single frame image is <Picture 1>.
With both, the first frame is <Picture 1> and the last frame is <Picture 2>. The
prompt guide shows the
alignment line Pika recommends.
Continuation
continue_from_clip_id continues a clip from this session, whichever way it was built.
continue_mode says how:
In a latent continuation, the end of the source clip is packed last, as a video reference. Its sound
takes the next audio label after all your other audio labels, but it does not use an audio slot. You
can still upload 3 audio clips: with three uploads and no reference video, the continued sound is
<Audio 4>. The end of the source clip does count as one of the 3 reference videos, so a latent
continuation accepts at most 2 reference videos, at most 12.67 seconds together.
Wait for the source clip’s clip_generated before you queue a latent continuation. You can queue a
frame continuation right away, even before its source has generated. It waits in the generation
queue until its source is built, and the clips behind it keep generating.
queue_update.history lists the built clips that left both queues. You can no longer play them, but
you can continue them. reset and the end of the session remove them.
Lengths
seconds and set_clip_seconds accept 25 values: 5, 5.167, 5.875, 6, 6.583, 7, 7.292, 8, 8.708, 9,
9.417, 10, 10.125, 10.833, 11, 11.542, 12, 12.25, 12.958, 13, 13.667, 14, 14.375, 15, and 15.083
seconds. The whole numbers are shortcuts: each one gives the shortest generated length at or above
it, so 5 gives 5.167 seconds, 8 gives exactly 8, and 15 gives 15.083. clip.seconds reports
the length the clip actually has. The model refuses any other value and does not round it. Read the
list from state_update.clip_seconds_choices rather than hard-coding it.
Limits
The model checks each request before it accepts it, and Refusals lists the codes. Each image can have at most 25 million pixels, with an aspect ratio between 1:4 and 4:1. Each upload can be at most 64 MiB, and a clip’s uploads at most 128 MiB together. The model refuses any field it does not take withinvalid_request.
clip_generated message and keep its clip.clip_id, then
enqueue the next clip with that ID. This request uploads one audio clip, so the continued clip’s
soundtrack becomes <Audio 2>:
<Picture 1>:
play
Play a ready clip. Leave out clip_id to play the clip at the front of the playout queue. The model
sends clip_started when the first frames reach the tracks and clip_finished when the clip ends.
A clip plays only once, and you cannot play it again afterward. You can continue from a clip in
queue_update.history, but you cannot play it.
stop
Cut the playing clip and leave the queues as they are. With autoplay on, stop skips to the next
ready clip. With flush on, the video cuts to black. With flush off, it holds the last frame once the
stream drains.
pop and move
Session settings
state_update carries the current defaults: clip_seconds is the current default length, and
clip_seconds_choices lists the allowed lengths. resolution is the current resolution, and
resolution_choices lists the ones you can set.
set_seed changes the seed for later clips. set_flush_on_clip_end takes effect at the next clip
boundary. get_state and get_queue reply with the same payload that the model broadcasts. reset
starts the session again from empty:
Refusals
When the model refuses a command, nothing changes and the call fails. Only the client that sent the command gets the error. It carries a stablecode and a reason you can show to your user.
request_rejected: the prompt is over the 2,048-token budget. The reason gives the count and the limit.invalid_image: a reference image or frame image does not decode.invalid_audio: an audio clip does not decode or is outside 2 to 15 seconds. This code also applies when the audio clips last more than 15 seconds together.invalid_request: the request breaks a rule that is not about one file. For example:- a length that is not offered
- too many references: more than 9 images, 3 videos, or 3 audio clips, or more than 12 in all
- frame images together with references, or a frame continuation with references or frame images
- reference audio without an image, a video, or a latent continuation
- a reference video that does not decode or is out of range, or videos that last more than 15 seconds together (the end of a latent-continued clip counts as 2.33 seconds)
- a
reference_orderthat does not name each upload once - a continuation ID that the model does not hold, or
continue_modewithout a continuation - an upload over the size limits, or a field that this model does not take
- a canvas or resolution change while the model prepares the request
no_ready_clip: the ID is unknown, the clip is still generating, or the playout queue is empty.has_dependents: queued clips continue from this clip, and it has not finished generating.session_not_empty: a clip is queued or playing, so the size cannot change.
error event fires with operation: "sendCommand" and the code, and then the
awaited call resolves undefined. Commands that declare a reply resolve undefined only when the
model refuses them. play and stop declare no reply and resolve undefined on success too, so
for these two only the error event shows a refusal. In Python, send_command() raises a
ReactorError with the code.
command_error message to every client when it refuses a command. That
broadcast is legacy. Read the refusal from the call instead. See
Replies and refusals.
Messages
A failed clip leaves the generation queue, and generation moves on to the next clip. In
clip_finished and clip_stopped, seconds_sent is the total for the session, not for one clip.
ClipInfo
Every message about a clip carries the full ClipInfo record. The first seven fields are always
present. The others are optional.