NEWVectors or files. Pick a path.Start →
    Safety and compliance
    Template v1.0 · updated 2026-09-03

    Video Moderation for Training Sets

    Reduce raw footage to the subset you can defend training on. Every excluded clip carries its reason, every uncertain one goes to a person, and the thresholds are yours.

    A cleared training set, with an audit trail for every clip that did not make it.

    Teams preparing video corpora for model training who have to prove what was excluded and why.

    82%
    of minors caught at a cutoff of 18
    on 650 labelled faces, 320 minors and 330 adults, single frame; 4.8% of adults sent to review
    100%
    recall is reachable, and the page says what it costs
    a cutoff of 30 catches every minor and sends 94.5% of adult footage to review; the whole curve is in the evaluation tab
    0.70
    face detector gate
    cleared six phantom minors the detector found in non-faces while keeping 85% of genuine faces
    39%
    of detections routed to review as unaged
    no usable face, under 24px, or detector confidence under 0.70. None of them is passed as adult.

    What it looks like

    Frame in, decisions fire, a verdict lands, a reviewer's call feeds back.

    Simulated walkthrough · illustrative frames, scripted decisions
    A close-up interview frame with one face in shotface 0.93 · est. 16 to 18 · borderlinereview
    faces -> age-estimation -> person-verdictsStill: Pexels / Ron Lachframe 1 of 4
    Decision path
    1. face detected 0.93
    2. grouped across 3 looks
    3. age estimate: borderline
    4. route: review
    within 6 years of the cutoff, and 3 looks
    Running tally
    0
    cleared
    1
    review
    0
    excluded
    Reviewer feedback
    When the frames are done, a reviewer's call on the borderline case feeds back into the thresholds.
    What goes in
    • source-video
      Your footage, read from your own object storage. Nothing is copied out.
    • brand-mark-refs
      Logo and mark variants you supply, one file per variant, with a hard-fail or contextual rule each.
    • person-refs
      Public-figure reference imagery you supply and hold the rights to. Several poses per person.
    Where the decisions fire
    Illustrative frames; boxes show the decision path, not live model output
    A close-up interview frame with one face in shotface 0.93 · est. 16 to 18 · borderlinereview
    faces -> age-estimation -> person-verdicts · A face is found, grouped with every other look at the same person across cuts, then aged. Borderline lands in review, never in the training set.Still: Pexels / Ron Lach
    A street scene with a lit storefront signbrand mark · match 0.88 · rule: contextualcleared
    keyframes -> brand-mark-match · A keyframe embedding is matched against your brand-mark reference index. The rule attached to that mark decides hard fail or contextual.Still: Pexels / Mathias Reding
    Two people sparring in a gymstaged 0.81 · real 0.19 · margin +0.62cleared
    keyframes -> violence-context · Violence is scored in context. Sparring, practice and play score staged; the real thing scores real. The margin between them is what you set.Still: Pexels / Franco Monsalvo
    A reporter beside a van carrying a BREAKING NEWS graphiconscreen_text · BREAKING NEWS · staticcleared
    onscreen-text · Words shown on screen and never spoken are read by the on-screen text pass, static overlays and scrolling bands alike, and land in their own searchable field. Nothing in the audio says BREAKING NEWS.Still: Pexels / cottonbro studio
    What comes out
    • segment-verdicts
      One row per segment: decision, the reason, and counts of people, minors, unaged and borderline faces.
    • review-queue
      Everything routed to a human, ranked, with the decision chain attached to each item.
    • cleared-set-export
      The segments you can train on, as a filterable set ready to hand to a training job.

    How the namespace is wired

    3 buckets, 8 collections, 2 clean views, 6 retrievers. The diagram generates the manifest below; they cannot drift apart.

    SourceBucketCollectionClean viewRetrieverClick a node to inspect it
    syncsyncsyncmultimodal_extractorimage_extractorface_identity_extractorface_identity_extractorimage_extractorscrolling_text_extractorage_estimatorcontext_scorersearchsearchtransformtransformpipeline inpipeline inpipeline inpipeline inpipeline outsearchsearchsearch

    One file spins up the namespace. Generated from the diagram above. Also served at /templates/video-moderation.namespace.yaml.

    # One file spins up the namespace. Wiring comes from the diagram:
    # edges are sync targets, source.bucket_ids, view sources and retriever scope.
    namespace: video-moderation
    sources:
      - name: source-video
        kind: s3
        cadence: continuous
        filters: your footage, in your account
        syncs_into: [source-video]
      - name: brand-marks
        kind: manual
        cadence: one-shot
        filters: customer-supplied logo and mark variants
        syncs_into: [brand-mark-refs]
      - name: person-references
        kind: manual
        cadence: one-shot
        filters: customer-supplied public-figure reference imagery
        syncs_into: [person-refs]
    buckets:
      - name: source-video
        skip_duplicates: true
        schema:
          content: { type: video }
      - name: brand-mark-refs
        skip_duplicates: true
        schema:
          content: { type: image }
      - name: person-refs
        skip_duplicates: true
        schema:
          content: { type: image }
    collections:
      - name: video-segments
        source: { type: bucket, bucket_ids: [source-video] }
        feature_extractor:
          feature_extractor_name: multimodal_extractor
          version: v2
          input_mappings:
            video: content
          field_passthrough:
            - { source_path: file_location }
            - { source_path: segment_id }
            - { source_path: start_time }
            - { source_path: end_time }
      - name: brand-mark-index
        source: { type: bucket, bucket_ids: [brand-mark-refs] }
        feature_extractor:
          feature_extractor_name: image_extractor
          version: v1
          input_mappings:
            image: content
          field_passthrough:
            - { source_path: mark_name }
            - { source_path: rule }
      - name: person-ref-index
        source: { type: bucket, bucket_ids: [person-refs] }
        feature_extractor:
          feature_extractor_name: face_identity_extractor
          version: v1
          input_mappings:
            image: content
          field_passthrough:
            - { source_path: person_name }
            - { source_path: rights_note }
      - name: faces
        source: { type: collection, collection_id: video-segments }
        feature_extractor:
          feature_extractor_name: face_identity_extractor
          version: v1
          input_mappings:
            video: content
          field_passthrough:
            - { source_path: segment_id }
            - { source_path: bbox }
            - { source_path: detection_score }
            - { source_path: quality_score }
      - name: keyframes
        source: { type: collection, collection_id: video-segments }
        feature_extractor:
          feature_extractor_name: image_extractor
          version: v1
          input_mappings:
            image: content
          field_passthrough:
            - { source_path: segment_id }
            - { source_path: frame_ts }
      - name: onscreen-text
        source: { type: collection, collection_id: video-segments }
        feature_extractor:
          feature_extractor_name: scrolling_text_extractor
          version: v1
          input_mappings:
            video: content
          field_passthrough:
            - { source_path: segment_id }
      - name: age-estimation
        source: { type: collection, collection_id: faces }
        feature_extractor:
          feature_extractor_name: age_estimator  # template-provided extractor, installed with the template
          version: v1
          input_mappings:
            face: content
          field_passthrough:
            - { source_path: person_id }
            - { source_path: age_median }
            - { source_path: aged }
            - { source_path: n_looks }
      - name: violence-context
        source: { type: collection, collection_id: keyframes }
        feature_extractor:
          feature_extractor_name: context_scorer  # template-provided extractor, installed with the template
          version: v1
          input_mappings:
            image: content
          field_passthrough:
            - { source_path: segment_id }
            - { source_path: staged_score }
            - { source_path: real_score }
            - { source_path: margin }
    clean_views:  # retriever_transform collections, the downstream contract
      - name: person-verdicts
        source: { type: collection, collection_ids: [faces, age-estimation] }
        retriever_transform:
          unique_id_field: person_id
          write_back_fields:
            - { source_field: age_median, target_field: age_median }
            - { source_field: aged, target_field: aged }
            - { source_field: n_looks, target_field: n_looks }
      - name: segment-verdicts
        source: { type: collection, collection_ids: [person-verdicts, violence-context, onscreen-text, video-segments] }  # via retriever pipeline
        retriever_transform:
          retriever: roll-up-by-segment  # the pipeline defines transform + doc identity
          unique_id_field: segment_id
          write_back_fields:
            - { source_field: decision, target_field: decision }
            - { source_field: reason, target_field: reason }
            - { source_field: n_person, target_field: n_person }
            - { source_field: n_minor, target_field: n_minor }
            - { source_field: n_unaged, target_field: n_unaged }
            - { source_field: n_borderline, target_field: n_borderline }
    retrievers:
      - name: brand-mark-match
        collections: [brand-mark-index]
        feature_search:
          fusion: rrf
          top_k: 5
          searches:
            - { feature_uri: "mixpeek://image_extractor@v1/google_siglip_base_v1", query: { input_mode: text, text: "{{INPUT.query}}" } }
      - name: public-figure-match
        collections: [person-ref-index]
        feature_search:
          fusion: rrf
          top_k: 5
          searches:
            - { feature_uri: "mixpeek://face_identity_extractor@v1/insightface__arcface", query: { input_mode: text, text: "{{INPUT.query}}" } }
      - name: roll-up-by-segment
        collections: [person-verdicts, violence-context, onscreen-text, video-segments]
        stages:  # pipeline retriever: groups documents, materialises into the collection on its out-edge
          - stage_name: group
            config: { stage_id: group_by, parameters: { group_by_field: segment_id } }
      - name: review-queue
        collections: [segment-verdicts]
        feature_search:
          fusion: rrf
          top_k: 100
          searches:
            - { feature_uri: "mixpeek://multimodal_extractor@v2/gemini-embedding-2", query: { input_mode: text, text: "{{INPUT.query}}" } }
      - name: moderation-search
        collections: [segment-verdicts]
        feature_search:
          fusion: learned
          top_k: 25
          searches:
            - { feature_uri: "mixpeek://multimodal_extractor@v2/gemini-embedding-2", query: { input_mode: text, text: "{{INPUT.query}}" } }
            - { feature_uri: "mixpeek://multimodal_extractor@v2/multilingual_e5_large_instruct_v1", query: { input_mode: text, text: "{{INPUT.query}}" } }
            - { feature_uri: "mixpeek://multimodal_extractor@v2/multilingual_e5_large_instruct_ocr_v1", query: { input_mode: text, text: "{{INPUT.query}}" } }
          learning_config: { shadow_mode: true, rollout_pct: 0.0, context_features: [INPUT.session_id] }  # flip via retriever PATCH when the signals justify it
      - name: cleared-set-export
        collections: [segment-verdicts]
        feature_search:
          fusion: rrf
          top_k: 1000
          searches:
            - { feature_uri: "mixpeek://multimodal_extractor@v2/gemini-embedding-2", query: { input_mode: text, text: "{{INPUT.query}}" } }