# gizai:flashhead

SoulX FlashHead lite, a talking head from one picture and speech, as its reference package and giz's worker run it.

The picture is cut around its face (MediaPipe's detector, gizai:video) and scaled to 512 x 512; LTX-Video 0.9's VAE (gizai:ltx) codes it, repeated over 33 frames, to a reference latent of 5 frames of 16 x 16. The speech goes in slices of 24 frames (15360 samples at 16 kHz). For each slice, the last 8 s of speech go through wav2vec 2.0 base (gizai:wav2vec), its 12 layers' states taken at 200 frames, and 5 states around each of the slice's 33 frames make 5 latent frames of 32 audio tokens. A Wan-style transformer (30 blocks of 1536, 12 heads, its rotary over frame, row and column) predicts the flow of the noisy latent, whose first latent frames are the motion of the slice before, in 4 steps; the VAE decodes 33 frames, their colors match the picture's (Lab means and deviations), and the last 9 are coded again as the next slice's motion. Each slice gives its last 24 frames.

```gizlang
import * as Flashhead from "gizai:flashhead";
```

## Types

### `FlashHead`

```gizlang
type FlashHead = { gpu: Gpu; blocks: Vec<Block>; patch: N.Linear; head: N.Linear; headMods: Vec<Tensor>; proj1: N.Linear; proj1vf: N.Linear; proj2: N.Linear; proj3: N.Linear; projNorm: Vec<Tensor>; cos: Tensor; sin: Tensor; ones: Tensor; zeros: Tensor; map: Tensor; w2v: W2.Encoder; vae: L.VideoVae; encoder: L.VideoEncoder09; faces: V.Faces; work: Scratch; }
```

The model where it runs.

- `gpu`: `M10.Gpu`
- `blocks`: `Vec<M23.Block>`
- `patch`: `M33.Linear`
- `head`: `M33.Linear`
- `headMods`: `Vec<M40.Tensor>` — At each step: the output norm's shift and scale ([2, 1536] F32).
- `proj1`: `M33.Linear`
- `proj1vf`: `M33.Linear`
- `proj2`: `M33.Linear`
- `proj3`: `M33.Linear`
- `projNorm`: `Vec<M40.Tensor>`
- `cos`: `M40.Tensor` — The rotary's angles at each row, [1280, 768] F32 (pair d of a head at column h 64 + d).
- `sin`: `M40.Tensor`
- `ones`: `M40.Tensor`
- `zeros`: `M40.Tensor`
- `map`: `M40.Tensor`
- `w2v`: `M45.Encoder`
- `vae`: `M30.VideoVae`
- `encoder`: `M30.VideoEncoder09`
- `faces`: `M44.Faces`
- `work`: `M23.Scratch`

### `Settings`

```gizlang
type Settings = { seed: i64; motion: f64; }
```

Settings of a job: the seed, the motion scale (1: the model's own; less keeps the face nearer the picture).

- `seed`: `i64`
- `motion`: `f64`

## Functions

### `load`

```gizlang
function load(sys: System, folder: string, gpu: Gpu): FlashHead throws string
```

FlashHead lite of `folder` (Model_Lite, VAE_LTX, wav2vec2-base-960h, face_detection_full_range_sparse.tflite) on
`gpu`.

Effects: fail, read, write, console, io.

### `speechOf`

```gizlang
function speechOf(sys: System, ffmpeg: string, path: string): Vec<f32> throws W.Failure
```

The speech of a file at 16 kHz, its channels averaged (ffmpeg decodes it).

Effects: fail, read, write, io.

### `serve`

```gizlang
function serve(sys: System, folder: string, place: Hosting.Place): i64 throws string
```

Serves FlashHead lite of `folder` as giz's worker at `place`: video.talking-head jobs. The kernels build and tune on
one slice of silence at the load, not in the first request (8 s more).

Effects: fail, read, write, console, io.

## Methods

### `FlashHead.picture`

```gizlang
function FlashHead.picture(self: FlashHead, image: Image.Image, crop: bool, ratio: f64): Vec<f32> throws string
```

The picture the model takes, as the reference makes it: RGB planes ([3, 512, 512]) of bytes as F32 in [0, 1].
With `crop`, the square around the first face (its width times `ratio`, centered across, its top half a side's
0.55 above the face's center, moved inside the picture), scaled by Pillow's BICUBIC; then (or without) scaled by
Pillow's BILINEAR to cover 512 x 512 and cut at the center.

Effects: fail, read, write, console, io.

### `FlashHead.talk`

```gizlang
function FlashHead.talk(self: FlashHead, picture: Vec<f32>, speech: Vec<f32>, s: Settings, out: mut V.H264, total: i64, alive: (step: i64, total: i64) => bool): void throws string
```

The frames of a talking head of `picture` (FlashHead.picture's planes) saying `speech` (16 kHz mono), pushed to
`out` slice by slice until it has `total`; `alive` false stops.

Effects: fail, read, write, console, io.

### `FlashHead.video`

```gizlang
function FlashHead.video(self: FlashHead, sys: System, ffmpeg: string, picture: Vec<f32>, speech: Vec<f32>, s: Settings, alive: (step: i64, total: i64) => bool): bytes throws string
```

An MP4 of the talking head of `picture` saying `speech` (16 kHz mono): H.264 at 25 fps, a frame for each 1 / 25 s
of speech, and the speech as AAC.

Effects: fail, read, write, console, io.

## Constants

### `MODEL`

```gizlang
const MODEL = "soulx-flashhead-lite"
```

The model id and operation of giz's worker.

### `OPERATION`

```gizlang
const OPERATION = "video.talking-head"
```

### `FPS`

```gizlang
const FPS = 25
```

The frames a second, and the speech's samples a second.

### `RATE`

```gizlang
const RATE = 16000
```

