dopetalk does not endorse any advertised product nor does it accept any liability for it's use or misuse


Our Discord Notification Server invitation link is https://discord.gg/jB2qmRrxyD

Author Topic: Deploying & Testing AI (PyTorch/CLIP & llama.cpp) + ffmpeg for ISEmedia Indexing  (Read 12 times)

Online Chip (OP)

  • Server Admin
  • Hero Member
  • *****
  • Administrator
  • *****
  • Join Date: Dec 2014
  • Location: Australia
  • Posts: 7339
  • Reputation Power: 0
  • Chip has hidden their reputation power
  • Gender: Male
  • Last Login:Today at 03:07:51 PM
  • Deeply Confused Learner
  • Profession: IT Engineer now retired
πŸ“Ž Click on me to view all attachments
ListAttBBC  |  v6.7.1  |  2026-09-01  |  Andrew.human & Claude.ai
#FileSizeDownloadsInfoDL
00Checkpoint-2026-09-01-llama-cpp-listatt-collabcore.md25.1 KB0ℹ️⬇️
01Project AI -- PyTorch-CLIP -- llama.cpp builds, rebuilds and ffmpeg -- Completed.pdf9.3 MB3ℹ️⬇️


New conversation, Gemini responds to Claude's checkpoint (attached):

πŸ“ Inline Markdown

Checkpoint locked in and fully understood. The massive overnight sprint successfully stabilized the PyTorch/CLIP stack, validated FFmpeg and llama.cpp/SmolVLM multimodal captioning on Live, overhauled search-query logging and rotation, and completed the ListAttBBC/CollabCore consolidation.

We are completely aligned with the standing constraints (preserving /usr/local/bin/python3.8, minding the 2GB RAM limit on Live, using \grep, and incrementing version numbers on all substantive revisions).


Immediate Next Steps for This Session

We can pick up directly with the prioritized task list from the checkpoint:

  • 1. Audio Transcription Test: Run Qwen3-ASR-0.6B against the extracted /root/video_audio.wav on Live using llama-mtmd-cli.

  • 2. Code & Alias Housekeeping:

  • Patch MiscSearch.py's hardcoded ISE_text_viewer.html reference to point at Sources/CollabCore/.

  • Update the cc shell alias from /var/www/html/CollabCore to the renamed /var/www/html/Collabware.

  • Verify that removing the vestigial qf_search_bridge.php exception from .htaccess causes no regressions.


  • 3. Core Integration:

Wire real CLIP vector embeddings and SmolVLM short captions intoΒ  MediaIndexer.py and MediaSearch.py's SimilarityRule to replace the mock media_store.json data.

Shall we kick things off by executing the Qwen3-ASR transcription test on Live, or would you prefer to knock out the quick path and alias patches first?



ChatGPT's Analysis:

πŸ“ Inline Markdown

Given that the toolchain is now operational, I would keep the ISEmedia design deliberately simple and modular. The key principle should be:

Classifier creates metadata β†’ Indexer stores/search-enables it β†’ Search queries it.

Do not build a giant monolithic AI pipeline yet. You have already established an incremental-development policy, and this is exactly where that pays off.

1. Proposed structure

ISEmedia/
β”‚
β”œβ”€β”€ ISEmediaClassifier.py
β”œβ”€β”€ ISEmediaIndexer.py
β”œβ”€β”€ ISEmediaSearch.py
β”‚
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ MediaDiscovery.py
β”‚   β”œβ”€β”€ MediaMetadata.py
β”‚   β”œβ”€β”€ ClipClassifier.py
β”‚   β”œβ”€β”€ VideoSampler.py
β”‚   β”œβ”€β”€ EmbeddingStore.py
β”‚   β””── SearchEngine.py
β”‚
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ index/
β”‚   β”œβ”€β”€ embeddings/
β”‚   β””── thumbnails/
β”‚
└── config/
    └── ISEmedia.conf

At this stage, the three primary scripts should remain independently runnable.


ISEmediaClassifier.py

Responsibility

Take a media file and produce an AI-enriched metadata record.

It should not worry about searching or database architecture.

Inputs

image
video
audio

Outputs

A structured record, initially JSON:

{
    "path": "/media/example.mp4",
    "type": "video",

    "technical_metadata": {
        "duration": 120.5,
        "width": 1920,
        "height": 1080,
        "codec": "h264"
    },

    "classification": {
        "labels": [
            ["person", 0.94],
            ["city", 0.82],
            ["night", 0.71]
        ]
    },

    "embedding": {
        "model": "CLIP",
        "vector_file": "..."
    }
}

Classifier pseudocode

INITIALISE configuration

LOAD CLIP model

FOR each input media file:

    DETERMINE media type

    EXTRACT basic filesystem metadata

    IF image:

        LOAD image

        GENERATE CLIP embedding

        RUN zero-shot classification
            USING configured vocabulary/prompts

        CREATE metadata record


    IF video:

        USE ffmpeg/ffprobe

        EXTRACT:
            duration
            resolution
            codec
            audio information

        SELECT representative frames

            simple initial algorithm:

                first frame
                25% frame
                50% frame
                75% frame
                final useful frame

        FOR each selected frame:

            GENERATE CLIP embedding

            RUN classification

        COMBINE frame results

            example:

                aggregate labels
                calculate mean/max confidence
                remove duplicates

        CREATE video metadata record


    IF audio:

        EXTRACT technical metadata with ffprobe

        CREATE basic metadata record

        [future AI audio analysis]


    SAVE metadata JSON

    SAVE embedding/vector

Video sampling

This deserves its own small component because video classification can otherwise become unnecessarily expensive.

v1 approach

Do not analyse every frame.

video
   β”‚
   β–Ό
ffprobe duration
   β”‚
   β–Ό
choose N timestamps
   β”‚
   β”œβ”€β”€ 0%
   β”œβ”€β”€ 25%
   β”œβ”€β”€ 50%
   β”œβ”€β”€ 75%
   β””── 95%
   β”‚
   β–Ό
ffmpeg extracts frames
   β”‚
   β–Ό
CLIP classifies frames
   β”‚
   β–Ό
aggregate results

Pseudocode:

FUNCTION sample_video(video, sample_count):

    duration = ffprobe(video).duration

    timestamps = evenly_spaced(
        0,
        duration,
        sample_count
    )

    FOR timestamp IN timestamps:

        frame = ffmpeg_extract_frame(
            video,
            timestamp
        )

        yield frame

Later versions can add:

scene detection
shot detection
motion detection
adaptive sampling

But not yet.


ClipClassifier.py

This should hide PyTorch and CLIP from the rest of the system.

The rest of ISEmedia should not care how the embedding is generated.

CLASS ClipClassifier:

    INITIALISE:

        load PyTorch

        load CLIP model

        load classification prompts


    FUNCTION classify(image):

        preprocess image

        image_embedding =
            CLIP.encode_image(image)

        FOR each configured label:

            text_embedding =
                CLIP.encode_text(label)

        similarity =
            compare(
                image_embedding,
                text_embeddings
            )

        RETURN ranked labels


    FUNCTION embed(image):

        RETURN CLIP.encode_image(image)

This abstraction will be valuable later if you change:

CLIP
   β†“
OpenCLIP
   β†“
local multimodal LLM
   β†“
other embedding model

The rest of the index remains unaffected.


ISEmediaIndexer.py

Responsibility

The Indexer consumes classifier output and creates the searchable index.

Its job is not to run ffmpeg or understand CLIP.

media files
     β”‚
     β–Ό
Classifier
     β”‚
     β–Ό
metadata records + embeddings
     β”‚
     β–Ό
Indexer
     β”‚
     β–Ό
ISEmedia index

For an initial version I would strongly recommend SQLite.

Not Elasticsearch.

Not a vector database server.

Not another daemon.

SQLite gives you:

one file
portable
backup-friendly
simple SQL
full text search
easy Python integration

Suggested initial schema

media
-----

id
path
filename
media_type
size
modified_time

duration
width
height

classifier_version
indexed_time
labels
------

media_id
label
confidence
embeddings
----------

media_id
model
vector

Depending on vector size, you can initially store the vector externally:

embeddings/

    000001.npy
    000002.npy
    000003.npy

with SQLite containing:

media_id
embedding_path
model

That keeps the initial implementation extremely simple.


Indexer pseudocode

OPEN SQLite database

CREATE tables if necessary

FOR each classifier metadata JSON:

    CHECK if media path already indexed

    IF existing:

        compare:

            modification time
            file size
            classifier version

        IF unchanged:

            SKIP


    INSERT or UPDATE media record


    DELETE old labels for media

    INSERT new labels


    REGISTER embedding location


COMMIT database

The important feature is incremental indexing.

IF file unchanged
    do nothing

You absolutely do not want to re-run CLIP across a large media collection unnecessarily.


ISEmediaSearch.py

This should initially provide two completely different search modes.

1. Metadata / keyword search

Example:

ISEmediaSearch.py "city night"

Conceptually:

SELECT media.*
FROM media
JOIN labels
WHERE labels.label IN (...)

2. Semantic CLIP search

Example:

ISEmediaSearch.py --semantic "people partying at night"

Pipeline:

user text
    β”‚
    β–Ό
CLIP text encoder
    β”‚
    β–Ό
text embedding
    β”‚
    β–Ό
compare against stored media embeddings
    β”‚
    β–Ό
rank by similarity

This is where your existing CLIP infrastructure becomes particularly useful.


Search pseudocode

PARSE command line

DETERMINE search type


IF keyword search:

    query SQLite labels

    rank results

    DISPLAY results


IF semantic search:

    LOAD CLIP

    text_embedding =
        CLIP.encode_text(user_query)

    LOAD stored embeddings

    FOR each embedding:

        similarity =
            cosine_similarity(
                text_embedding,
                media_embedding
            )

    SORT by similarity

    DISPLAY top N results

llama.cpp's role

I would not put llama.cpp in the critical indexing path initially.

Instead, use it as an optional intelligence layer.

For example:

User:
    "find videos that look like old nightclub footage"

             β”‚
             β–Ό

          llama.cpp

             β”‚
             β–Ό

Query interpretation

    {
        media_type: "video",
        concepts: [
            "nightclub",
            "crowd",
            "night",
            "indoor"
        ]
    }

             β”‚
             β–Ό

CLIP semantic search

Or:

User natural language
        β”‚
        β–Ό
llama.cpp
        β”‚
        β–Ό
structured search plan
        β”‚
        β”œβ”€β”€ keyword filters
        β”‚
        β”œβ”€β”€ metadata filters
        β”‚
        └── semantic query

That should be ISEmedia v2, not the first functioning version.


Overall architecture

                     MEDIA LIBRARY
                          β”‚
                          β–Ό
                  ISEmediaClassifier
                          β”‚
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             β”‚                         β”‚
             β–Ό                         β–Ό
        SQLite metadata           CLIP vectors
             β”‚                         β”‚
             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                          β–Ό
                   ISEmediaSearch
                          β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                       β”‚
              β–Ό                       β–Ό
        Keyword Search          Semantic Search
              β”‚                       β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                          β–Ό
                       Results

The minimal implementation sequence

I would implement this in exactly this order:

Phase 1 β€” Classifier

image β†’ CLIP labels β†’ JSON

Prove that this works.

Phase 2 β€” Embeddings

image β†’ CLIP embedding β†’ vector file

Prove semantic similarity works.

Phase 3 β€” Indexer

JSON β†’ SQLite
vector β†’ registered

Phase 4 β€” Image Search

text β†’ CLIP β†’ similarity search

Phase 5 β€” Video

video
β†’ ffprobe
β†’ sample 5 frames
β†’ CLIP
β†’ aggregate
β†’ index

Phase 6 β€” Natural-language layer

user query
β†’ llama.cpp
β†’ search plan
β†’ keyword + semantic search

My strongest recommendation

Keep the first version constrained to this contract:

Classifier:
    media β†’ metadata + embedding

Indexer:
    metadata + embedding β†’ searchable index

Search:
    query β†’ ranked media results

That gives you three independently testable programs with clean boundaries. Once that works, we can incrementally define the actual ISEmedia metadata schema and SQLite schema, then turn this pseudocode into the first working scripts without destabilising the underlying architecture.

« Last Edit: Today at 02:19:54 PM by Chip »
friendly
0
funny
0
informative
0
agree
0
disagree
0
like
0
dislike
0
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
Our Discord Server invitation link is https://discord.gg/jB2qmRrxyD

Offline smfadmin

  • SMF (internal) Site
  • Administrator
  • Sr. Member
  • *****
  • Join Date: Dec 2014
  • Location: Management
  • Posts: 604
  • Reputation Power: 0
  • smfadmin has hidden their reputation power
  • Last Login:Today at 02:29:55 PM
  • Supplied Install Member
πŸ“ Inline Markdown
ffmpeg -i /root/instagram-1787449936704.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 /root/video_audio.wav -y


Code: [Select]
Live  root@forum:14:04:04:~# sh speech_to_text.sh

0.02.351.629 W common_fit_params: failed to fit params to free device memory: was unable to fit model into system memory by reducing context, abort
0.02.873.340 W load: control-looking token: 128247 '</s>' was not control-type; this is probably a bug in the                model. its type will be overridden
0.05.024.850 I cmn          init: llama threadpool init, n_threads = 2
0.06.061.412 W init_audio: audio input is in experimental stage and may have reduced quality:
    https://github.com/ggml-org/llama.cpp/discussions/13759
0.06.074.596 I mtmd_cli_context: chat template example:
<|im_start|>system
You are a helpful assistant<|im_end|>
<|im_start|>user
Hello<|im_end|>
<|im_start|>assistant
Hi there<|im_end|>
<|im_start|>user
How are you?<|im_end|>
<|im_start|>assistant

0.06.074.608 I main: loading model: /root/models/qwen3-asr/Qwen3-ASR-0.6B-Q8_0.gguf
0.06.078.034 W WARN: This is an experimental CLI for testing multimodal capability.
0.06.078.041 W       For normal use cases, please use the standard llama-cli
0.08.140.806 I encoding mtmd batch, n_chunks = 1 (done = 1, total = 14)
0.11.232.976 I mtmd batch encoding done in 3092 ms
0.16.468.200 I encoding mtmd batch, n_chunks = 1 (done = 2, total = 14)
0.19.719.630 I mtmd batch encoding done in 3251 ms
0.25.731.461 I encoding mtmd batch, n_chunks = 1 (done = 3, total = 14)
0.28.800.837 I mtmd batch encoding done in 3069 ms
0.34.758.253 I encoding mtmd batch, n_chunks = 1 (done = 4, total = 14)
0.37.763.929 I mtmd batch encoding done in 3005 ms
0.44.104.466 I encoding mtmd batch, n_chunks = 1 (done = 5, total = 14)
0.47.013.779 I mtmd batch encoding done in 2909 ms
0.53.050.953 I encoding mtmd batch, n_chunks = 1 (done = 6, total = 14)
0.57.008.452 I mtmd batch encoding done in 3958 ms
1.03.385.914 I encoding mtmd batch, n_chunks = 1 (done = 7, total = 14)
1.06.597.537 I mtmd batch encoding done in 3212 ms
1.12.884.325 I encoding mtmd batch, n_chunks = 1 (done = 8, total = 14)
1.15.742.540 I mtmd batch encoding done in 2858 ms
1.21.756.724 I encoding mtmd batch, n_chunks = 1 (done = 9, total = 14)
1.24.355.930 I mtmd batch encoding done in 2599 ms
1.30.117.221 I encoding mtmd batch, n_chunks = 1 (done = 10, total = 14)
1.32.692.071 I mtmd batch encoding done in 2574 ms
1.39.038.705 I encoding mtmd batch, n_chunks = 1 (done = 11, total = 14)
1.41.622.475 I mtmd batch encoding done in 2584 ms
1.47.805.957 I encoding mtmd batch, n_chunks = 1 (done = 12, total = 14)
1.48.660.393 I mtmd batch encoding done in 855 ms

language English<asr_text>

This algorithm teaches every AI everything it knows, and it's really just a chain ru               le from your first calculus class. It's called back propagation, and its job is to figure out which parts of t               he network to blame when something goes wrong. Say the network reads a handwritten three and then confidently                thinks it's a seven. The loss function hands the network the penalty for that mistake. But that prediction cam               e from a hundred thousand weights, and the network has no idea which of them actually pushed it towards guessi               ng seven. So back propagation splits that blame up weight by weight. Let's start at the output. Say the networ               k was ninety percent sure about its wrong guess seven. The right answer was zero percent, so the seven's blame                is the whole ninety. Then it walks that blame backwards one layer at a time, using the same weights the predi               ction used, and at every step it multiplies the blame by that neuron's slope. This is just the chain rule. You               're really just multiplying all the slopes together all the way back to the pixels. And by the end, every weig               ht knows its exact share of the mistake. And this is what the code for that looks like. Now here's my favorite                part. When I first learned this, the obvious way to measure blame would be to nudge one weight, rerun the who               le network, and then watch the error move. But with a hundred thousand weights, that's a hundred thousand runs                for just one single digit. Back propagation is able to get them in a single pass, which is the entire reason                we can even train models like GPT three, which have over a hundred and seventy five billion weights. But back                propagation only finds the blame and it doesn't really fix anything. Gradient descent does the fixing, and it'               s really just one line of code that nudges every weight a tiny step against its blame. Next time I'll show you                how to build your own neural network from scratch using just Python. So save this and share this with a frien               d who wants to learn it from scratch.


/root/llama.cpp/build/bin/llama-mtmd-cli \
-m /root/models/qwen3-asr/Qwen3-ASR-0.6B-Q8_0.gguf \
--mmproj /root/models/qwen3-asr/mmproj-Qwen3-ASR-0.6B-Q8_0.gguf \
--audio /root/video_audio.wav \
-p "Transcribe this audio then summarize it in 7 words or less"

exit 0
: <<'DOC'
see below
DOC

πŸ“ Inline Markdown

Okay, let's slow that part right down with a concrete walkthrough.

Step 1 β€” chop the image into a grid

Take your actual photo, say 224Γ—224 pixels. It gets cut into a grid of small square tiles β€” say 16Γ—16 pixels each. That gives you a 14Γ—14 grid = 196 tiles total. Each tile is just a small patch of the picture β€” a little square of pixel colors, nothing more.

Step 2 β€” flatten each tile into numbers

Each tile is really just a grid of red/green/blue pixel values. A 16Γ—16 tile with 3 color channels is 16Γ—16Γ—3 = 768 raw numbers. So right now, each patch is a list of 768 numbers describing its raw colors β€” not meaningful yet, just pixel data unrolled into a line of numbers.

Step 3 β€” the vision encoder turns "raw pixels" into "meaning"

Those 768 raw numbers get pushed through a trained neural network (the vision encoder β€” think of it as its own separate mini-model bolted onto the front). This network was trained on millions of images to compress each patch into a new vector β€” say 768 numbers again, but now those numbers represent learned visual features rather than raw color values: things like "this patch has an edge running diagonally," "this patch looks like skin texture," "this patch has a round pale shape" β€” except it's not literally labeled that way, it's just numbers that the networkΒ  has learned cluster in useful, meaningful ways when similar visual patterns appear.

This is the exact same idea as CLIP's image embedding you're already using for similarity search β€” same kind of process, same kind of output vector.

Step 4 β€” those patch-vectors get treated exactly like word-vectors

Now you've got 196 vectors (one per patch), each the same "shape" (same length list of numbers) as a word-token vectorΒ  would be. The model doesn't know or care that these came from an image instead of text β€” it just sees a sequence of 196 vectors, followed by however many word-vectors your prompt ("Describe this image in 5 words") produces.

Step 5 β€” the language model just predicts words, as usual

The language model then does the exact same thing it always does: look at the whole sequence of vectors it's been given (image-patch vectors + prompt-word vectors) and predict the next most likely word, over and over, to build the caption. It learned during training β€” on huge datasets of real image+caption pairs β€” which patterns across those 196 image vectors tend to go with which words in captions.

So the "confusing" part β€” how a picture becomes something a text model can respond to β€” really comes down to: chop it into tiles β†’ run each tile through a separate trained network that turns pixels into meaningful-number vectors β†’ hand those vectors to the language model as if they were just more words in the sentence.

« Last Edit: Today at 02:58:16 PM by Chip »
friendly
0
funny
0
informative
0
agree
0
disagree
0
like
0
dislike
0
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
No reactions
measure twice, cut once

Tags:
 

Related Topics

  Subject / Started by Replies Last post
3 Replies
40044 Views
Last post July 21, 2015, 04:01:15 AM
by Chip
8 Replies
47205 Views
Last post August 02, 2017, 04:32:38 PM
by Chip
3 Replies
36513 Views
Last post December 02, 2017, 10:16:46 PM
by dillydudeEL14
0 Replies
19832 Views
Last post July 25, 2018, 09:11:05 AM
by Chip
14 Replies
69267 Views
Last post December 29, 2018, 04:20:49 AM
by MoeMentim
0 Replies
22942 Views
Last post May 27, 2021, 09:52:11 PM
by Chip
0 Replies
18587 Views
Last post August 25, 2021, 10:30:26 PM
by Chip
0 Replies
24386 Views
Last post June 03, 2023, 11:05:22 AM
by Chip
2 Replies
21047 Views
Last post December 31, 2025, 11:35:30 AM
by Chip
2 Replies
779 Views
Last post June 11, 2026, 11:44:10 AM
by Chip


dopetalk does not endorse any advertised product nor does it accept any liability for it's use or misuse





TERMS AND CONDITIONS

In no event will d&u or any person involved in creating, producing, or distributing site information be liable for any direct, indirect, incidental, punitive, special or consequential damages arising out of the use of or inability to use d&u. You agree to indemnify and hold harmless d&u, its domain founders, sponsors, maintainers, server administrators, volunteers and contributors from and against all liability, claims, damages, costs and expenses, including legal fees, that arise directly or indirectly from the use of any part of the d&u site.


TO USE THIS WEBSITE YOU MUST AGREE TO THE TERMS AND CONDITIONS ABOVE


Founded December 2014
SimplePortal 2.3.6 © 2008-2014, SimplePortal