Commit Graph
404 Commits
Author SHA1 Message Date
Victor KuznetsovandClaude Opus 5 7234cf7f4d Release 0.23.0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v0.23.0
2026-08-02 21:29:34 -07:00
Victor KuznetsovandGitHub db33823d8e Merge pull request #74 from wiltodelta/feat/sdxl-zimage-profile
Add the sdxl-zimage profile: the same recipe on an SDXL global stage
2026-08-02 21:27:54 -07:00
Victor KuznetsovandClaude Opus 5 a9e64b9628 Add the sdxl-zimage profile: the same recipe on an SDXL global stage
SdxlZImagePipeline subclasses QwenZImagePipeline and overrides only _run_global
and preload, so the face stage is inherited rather than copied and cannot drift
between the two profiles. A test asserts the shared methods are the same objects.

Four things are architecture-bound and swap with the model: the ControlNet, the
four-step distillation LoRA (SDXL-Lightning at its documented 1.0, not the
reference graph's 0.8, which belongs to a different LoRA), the sampler (Euler
trailing, no AuraFlow shift), and the latent grid at 8 px against Qwen's 16.

Strength is architecture-bound too, which is the easy mistake and cost two wrong
conclusions before it was caught. An SDXL global pass leaves SynthID at the
strength Qwen needs: through the Gemini app on a native 2816x1536 original, 0.154
is FOUND while 0.20, 0.25 and 0.30 are clean. The profile therefore takes a flat
vendor policy - OpenAI 0.15, Gemini 0.25, unknown following Gemini - rather than
resolution_adaptive_denoise, because flat values are what was measured and no
size dependence has been established for this stage.

requested_steps exists because the runtimes truncate differently: DiffSynth sets
sigma_start = denoising_strength and runs every requested step, while Diffusers
img2img truncates the step count, so four steps at 0.15 executes zero and returns
a bare VAE round-trip.

Also records both measured provider boundaries for the shipped qwen-zimage curve
- OpenAI detected at 0.06 and clean from 0.08, Gemini detected at 0.08 and clean
from 0.10 - together with the two low-resolution Gemini verdicts that explain why
the curve's sub-1 MP rungs are not under-driven despite looking short against a
boundary measured at 4.33 MP. The curve is left unchanged; nothing measured fails.

The profile is not deployed and not production-ready: every verdict so far comes
from one fixture and one seed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 21:23:43 -07:00
Victor KuznetsovandGitHub a4d8de4367 Merge pull request #73 from wiltodelta/docs/face-stage-compositing
Document how the face stage actually composites
2026-08-02 20:47:57 -07:00
Victor KuznetsovandClaude Opus 5 af51afb586 Document how the face stage actually composites
The parameter names invite a misreading. _run_faces regenerates the ENTIRE
expanded crop with Z-Image and only then cross-fades on a blurred SAM mask, so
the generation is conditioned on a fully noised neighbourhood and the pixels the
mask later discards were regenerated too.

Records the alternative that has never been tried here - passing the mask into
the sampler as a latent noise mask, so only masked pixels are denoised and the
edge transition happens inside the generation - because the face stage is the
largest measured quality contributor, worth 3.5 dB and 6.1 dB inside the face
boxes on the two fixtures that have one.

Also records that FACE_DENOISE_SCALE = 0.5 is coupled to this compositing choice
rather than independently calibrated: regenerating a whole crop and blending is
stronger than masked denoising, so changing the compositing without revisiting
the scale would move output strength by about a factor of two.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 20:44:20 -07:00
Victor KuznetsovandGitHub f51c5b09dd Merge pull request #72 from wiltodelta/docs/qwen-zimage-denoise-boundary
Record the qwen-zimage global denoise boundary against the Gemini oracle
2026-08-02 20:16:58 -07:00
Victor KuznetsovandClaude Opus 5 9b07b3f0ec Validate the bottom of the qwen-zimage denoise curve against Gemini
Downscaled a Gemini original to 0.57 and 1.40 MP and ran the deployed worker on
both, so the profile applied its own low-end strengths of 0.0896 and 0.1066. Both
come back clean in the Gemini app.

That rules out the failure mode the ladder raised: 0.08 failed at 4.33 MP, and the
curve sends sub-1 MP images to 0.084-0.094, which looked like it might mean small
Gemini uploads were under-processed in production. They are not, at these sizes.

Written as validation of the shipped curve rather than as evidence that the
boundary moves with resolution. 0.0896 sits inside the untested gap at 4.33 MP,
where only 0.08 and 0.10 were probed, so it may clear at both sizes; the direction
of any resolution dependence stays unproven. These are also downscales rather than
natively small Gemini outputs, which remain untested.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:53:51 -07:00
Victor KuznetsovandClaude Opus 5 84583dd479 Drop the unproven claim that Gemini removal is resolution-sensitive
The document asserted it in two places and recommended capping Gemini at 1536
with 0.30, or native-calibrating to ~0.35+. Nothing measured that, and the one
relevant measurement points the other way: the 2026-06-14 deployed-worker re-test
cleared Gemini at 0.15 on two NATIVE 2816x1536 images, the same rung as capped
1536. The document already recorded that as contradicting the "native >= 0.30"
guess, then kept the guess anyway in the historical-certification paragraph and
restated it as fact in the strength floors.

Replaced with what was measured, plus an explicit statement that the direction is
unproven and the low-resolution end has never been through the Gemini oracle on
any pipeline.

Also removes the same appeal from the qwen-zimage denoise-boundary note added
earlier in this branch, which had used the unproven trend as reassurance that the
bottom of the adaptive curve is safe. It is not reassurance; it is an open
question, and it is now written as one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:49:44 -07:00
Victor KuznetsovandClaude Opus 5 56d7aff3a1 Record the qwen-zimage global denoise boundary against the Gemini oracle
A ladder on one native 2816x1536 Gemini original at seed 0, verified through the
Gemini app, puts the boundary between 0.08 and 0.10: 0.154, 0.12 and 0.10 read
clean, 0.08 reads SynthID FOUND. Fidelity rises monotonically all the way down,
so 0.10 buys +1.54 dB whole-image and +0.98 dB inside the face boxes over the
0.154 the profile ships for that size.

Recorded with the two constraints that stop it being acted on directly. It
brackets rather than calibrates - one image, one seed, and shipping the lowest
clean rung means shipping at the measured cliff edge. And the untested end is the
bottom, not the top: every Gemini oracle fixture is 2816x1536, so the Google-side
certification only ever covered 0.154, while the curve sends sub-1 MP images to
0.084-0.094. The resolution trend already recorded in this document says lower
processing resolution needs less strength, which is the shape the curve has, but
that is an inference and no small Gemini original has ever been through the
oracle. Downscaling is valid test material since SynthID survives it by design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:46:12 -07:00
Victor KuznetsovandGitHub 40cd122683 Merge pull request #71 from wiltodelta/feat/static-prompt-embedding-cache
Serve the static prompt embeddings from a persistent cache
2026-08-02 15:39:37 -07:00
Victor KuznetsovandClaude Opus 5 39523aba09 Serve the static prompt embeddings from a persistent cache
Both qwen-zimage stages prompt with module constants, and at CFG 1.0 DiffSynth's
PipelineUnitRunner reuses the positive embedding for the negative side rather
than encoding it, so exactly one embedding per stage is ever computed. Persist it
and neither text encoder has to be loaded at all.

Measured on an H100 volume: this drops 15.45 GiB (Qwen2.5-VL) and 7.49 GiB
(Z-Image) of an 87.6 GiB per-request read, worth a median 11.76 s and 4.10 s of
load time paired within five containers. A nine-face fixture returned
sha256 c8567e11077de32a both with and without the cache, so the output is
byte-identical and the provider-oracle clearance is untouched.

The cache key carries the cache version, model id, pipeline output params and the
exact prompt, so a model bump or a prompt edit recomputes instead of reading a
stale embedding. The write is atomic because a torn file must never read back as
a hit, and a miss after the text encoder was already dropped raises rather than
calling a model that is not loaded.

_model_cache_dir now prefers HF_HOME: on a scale-to-zero runner that is the only
persistently mounted path, so anything below it is re-derived every request. The
YuNet download follows the same root.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 15:36:55 -07:00
Victor KuznetsovandClaude Opus 5 94730f77d3 Merge the v0.20.1 residency fix into main
Joins fix/qwen-vram-residency, which carried the global-stack residency
change on the v0.20.1 line that raiw-app pins. The change itself is already
on main via port/qwen-vram-residency-main, reapplied there because the
package layout moved under _internal/ in between, so this merge is history
only and its tree is identical to the commit before it.

Conflicts resolved in favour of main throughout, including dropping the
noai/watermark_remover.py the branch resurrected; that module now lives at
_internal/watermark_remover.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 21:53:40 -07:00
Victor KuznetsovandClaude Opus 5 36e3743289 Keep the qwen-zimage global stack resident on a card that can hold it
Port of the same change made on the v0.20.1 line, reapplied here because the
package layout moved under _internal/ in the meantime.

The mandatory Qwen stack was configured to offload to disk unconditionally.
DiffSynth implements that by dropping the weights to the meta device and
re-reading every parameter through its DiskMap on the next onload, and the
pipeline moves between text encoder, transformer and VAE on every pass, so
each generation paid a full model reload. That is the right trade on a
consumer card, where it is what makes a 20B model runnable at all, and pure
waste on a card that can simply hold the stack.

Residency is now resolved from total VRAM, mirroring how the optional
Z-Image face stack is already gated. Above the floor the config passes no
"disk" value anywhere, which is what actually disables the behavior:
DiffSynth latches disk_offload once from offload_dtype, so pointing every
device at CUDA while leaving the sentinel would keep both the meta-drop and
the re-read.

Measured on an H100: a warm global pass went from 37.3s at 0.8 GiB resident
to 2.2s at 28.7 GiB, with both stacks resident peaking at 48.0 GiB of 79.2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 21:22:52 -07:00
Victor KuznetsovandClaude Opus 5 a64d81f446 Keep the qwen-zimage global stack resident on a card that can hold it
The mandatory Qwen stack was configured to offload to disk unconditionally.
DiffSynth implements that by dropping the weights to the meta device and
re-reading every parameter through its DiskMap on the next onload, and the
pipeline moves between text encoder, transformer and VAE on every pass, so
each generation paid a full model reload. That is the right trade on a
consumer card, where it is what makes a 20B model runnable at all, and pure
waste on a card that can simply hold the stack.

Residency is now resolved from total VRAM, mirroring how the optional
Z-Image face stack is already gated. Above the floor the config passes no
"disk" value anywhere, which is what actually disables the behavior:
DiffSynth latches disk_offload once from offload_dtype, so pointing every
device at CUDA while leaving the sentinel would keep both the meta-drop and
the re-read.

The floor is set equal to the face floor rather than lower because that is
the configuration measured with both stacks resident; a tighter gate is
plausible but unvalidated. cpu_offload now forces both stacks to stream, so
a caller asking for low VRAM no longer gets the larger stack pinned anyway.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
raiw-app-pin-20260802
2026-08-01 21:06:13 -07:00
Victor Kuznetsov 9c71dc9c79 Refresh dependencies and compatibility guards 2026-07-31 17:24:05 -07:00
Victor KuznetsovandGitHub be7553b55f Merge pull request #70 from wiltodelta/feat/video-watermarks
Complete product video watermark pipeline
2026-07-31 17:00:56 -07:00
Victor Kuznetsov a6c0c1c6f0 Rewrite internal watermark pipeline and preserve behavior 2026-07-31 16:53:41 -07:00
Victor Kuznetsov 7c922e5133 Preserve one encoded frame per input frame 2026-07-31 15:31:00 -07:00
Victor Kuznetsov 7e63856a90 Split video encoding from audio muxing 2026-07-31 15:22:41 -07:00
Victor Kuznetsov 9b9f9c6ced Open source input before frame pipe 2026-07-31 15:07:15 -07:00
Victor Kuznetsov 7818e60824 Prevent ffmpeg stderr backpressure 2026-07-31 14:59:57 -07:00
Victor Kuznetsov 0fac8cd000 Bound ffmpeg filter threads 2026-07-31 14:43:01 -07:00
Victor Kuznetsov 166dab9d03 Bound ffmpeg video encoder threads 2026-07-31 14:33:50 -07:00
Victor Kuznetsov 7fb0e65455 Trace stalled Linux video encoder 2026-07-31 14:24:08 -07:00
Victor Kuznetsov 1fd859b58d Prevent ffmpeg pipe probe deadlock 2026-07-31 12:05:42 -07:00
Victor Kuznetsov f9a4e2ba10 Diagnose stalled video end-to-end test 2026-07-31 11:54:45 -07:00
Victor Kuznetsov 0e7a52820b Bound full-clip video CI runtime 2026-07-31 11:30:57 -07:00
Victor Kuznetsov de3ed75de5 Merge main into video watermark pipeline 2026-07-31 11:13:59 -07:00
Victor Kuznetsov 5767c1d7b3 Finalize video package boundary and product wording 2026-07-31 10:52:44 -07:00
github-actions[bot] 63d7cfa0a5 Sync conda recipe with v0.22.0 2026-07-31 17:43:40 +00:00
Victor Kuznetsov 6315b58628 feat: complete product video watermark pipeline 2026-07-31 10:42:39 -07:00
Victor Kuznetsov 08dc078d91 Release 0.22.0 with composable feature extras v0.22.0 2026-07-31 10:39:13 -07:00
Victor Kuznetsov 8975916b11 Harden automatic video watermark removal for product use 2026-07-30 18:36:04 -07:00
Victor Kuznetsov 9c9e81c756 Compact CLAUDE.md and route development guidance 2026-07-30 18:32:25 -07:00
Victor Kuznetsov fc177bacde Correct OpenCV Dependabot compatibility cutoff 2026-07-30 18:18:49 -07:00
Victor Kuznetsov 0c4b26bb77 Fix OpenCV Dependabot compatibility bound 2026-07-30 16:29:29 -07:00
Victor Kuznetsov 3d941069e5 Keep Dependabot updates within compatible dependency lines 2026-07-30 16:21:50 -07:00
Victor Kuznetsov 4e97076b22 Merge external metadata evidence into main 2026-07-30 12:49:06 -07:00
Victor Kuznetsov 07b678fa4c Add Hailuo, Kling, AVI, and FLV video coverage 2026-07-29 23:30:33 -07:00
Victor Kuznetsov 63cde7f32a Add streaming video SynthID regeneration 2026-07-29 22:03:23 -07:00
Victor Kuznetsov c9b8585105 Add video SynthID experiment harness 2026-07-29 21:03:46 -07:00
Victor Kuznetsov 41b6fd0682 Add Seedance and Dola video removal 2026-07-29 17:56:52 -07:00
Victor Kuznetsov f330dd9c94 Add video metadata and visible watermark removal 2026-07-29 17:28:11 -07:00
github-actions[bot] a67b209d66 Sync conda recipe with v0.21.2 2026-07-29 23:48:36 +00:00
Victor Kuznetsov 7c9bec0eba Ignore collector diagnostics in metadata evidence v0.21.2 2026-07-29 16:46:42 -07:00
github-actions[bot] 37f3b3b1c9 Sync conda recipe with v0.21.1 2026-07-29 21:34:11 +00:00
Victor Kuznetsov 4ef180541f Add external metadata evidence ingestion v0.21.1 2026-07-29 14:32:25 -07:00
github-actions[bot] c013704ded Sync conda recipe with v0.21.0 2026-07-29 20:17:17 +00:00
Victor Kuznetsov 408c4c9d5d Separate provenance extraction and detection, release 0.21.0 v0.21.0 2026-07-29 13:13:39 -07:00
github-actions[bot] 28d23a3023 Sync conda recipe with v0.20.2 2026-07-28 19:14:22 +00:00