{% extends "admin/_layout.html" %} {% from "_macros.html" import icon %} {% set section = "extraction" %} {% block title %}Extraction - {{ brand.name }}{% endblock %} {% block heading %}Extraction and search{% endblock %} {% block admin_content %}

What happens to a file between the upload and the model, and how anything is found again afterwards. The two are the same pipeline: what is extracted decides what there is to search.

{% if saved %}
{{ icon("check", "icon--sm") }} {{ saved }}
{% endif %} {# --- Extraction ----------------------------------------------------------- #}

What a file may cost

Every number here is a trade, and a large one usually breaks a request rather than being slow — the text of a whole book does not fit in a context window, and a model handed it fails the request outright rather than reading the first half.

Megabytes, before anything is done to it.

Characters. Roughly four to a token, so 120,000 is about 30,000 tokens — already most of a small context window. The rest is cut and the model is told so.

Extraction is slow and happens once, at upload. Beyond this the file is still stored; only its text stops.

Pixels. Images are re-encoded before they are sent, because a phone photo is several megabytes of base64.

Hours. A file chosen in the composer and never sent. Swept at startup.

One extension per line, .env or env. Only needed to pick a media type — whether the bytes decode as text is what actually decides, so an unlisted extension already works.

Off, a scanned PDF is stored with an explanation saying why it contributes nothing — there is no OCR here. That is usually what somebody wants: the file is still attached and still downloadable.

{# --- Semantic search ------------------------------------------------------ #}

Searching by meaning

Keyword search finds a document that uses your words. This finds one that means the same thing — "how do I get in" reaching a note about passwords. Both run and the two rankings are fused, so nothing that keyword search found is lost.

{% if not models %}
{{ icon("warning", "icon--sm") }} No model is marked as producing embeddings. Tick embeddings on one under Models — usually a small dedicated model such as nomic-embed-text or bge-m3, not a chat model.
{% endif %} {% if missing_model %}
{{ icon("warning", "icon--sm") }} {{ missing_model }} is selected but is not available — its model or its connection has gone, or it is no longer marked for embeddings. Search has fallen back to keywords.
{% endif %}

None is not a degraded mode: it is the keyword search this has always had, with nothing stored and nothing sent anywhere. Changing the model changes what a vector means, so anything already indexed is ignored until it is rebuilt.

Characters. A record is split on paragraph boundaries into pieces of about this size, and each is embedded separately — a document is found by its best piece, not by its average.

How much of each piece is repeated at the start of the next, so a sentence across a boundary is whole somewhere. Capped at half the piece size.

Lower this if the endpoint refuses large requests; raise it if a rebuild is slow and the far side has room.

{# --- The index ------------------------------------------------------------ #}

The index

Documents, notes, skills and reports are indexed as they are written. A rebuild is for everything that already existed — or for after changing the model or the piece size, both of which make what is stored stop meaning anything. It runs in the background and can be left.

{% include "admin/_index_progress.html" %}
{% endblock %}