{% extends "base.html" %} {% block title %}Settings & checks — Video to LLM{% endblock %} {% block content %} {# Defaults rather than hard dependencies. Jinja loads templates from disk on every request while route code lives in the running process's memory, so an upgraded checkout served by a server started before the upgrade renders a new template against an old context. Depending on a variable the old route never passed turns that into a 500 on a screen the user is trying to reach. `settings` is passed by every route, in every version, so it is the safe fallback for the form's current values. #} {% set draft = draft | default(settings, true) %} {% set problems = problems | default([], true) %} {% set health = health | default(none, true) %} {% set saved = saved | default(false, true) %} {% set root_blocker = root_blocker | default("", true) %} {% set running_port = running_port | default(settings.port, true) %}

Settings & checks

How this computer is set up, and what is working.

This computer

{% for check in report.checks %} {% endfor %}
Readiness checks
{{ check.title }} {{ check.detail }}
{% if saved %}

Saved. New jobs will use these settings.

{% endif %} {% if problems %} {% endif %}

Describing what is on screen

Optional

Off unless you turn it on. A job without descriptions still produces pictures and a transcript, and you can add descriptions later without redoing anything.

Which model should describe them?
On this computer

Frames stay on this device. No provider API charge. Local compute, battery, heat, memory use, and processing time apply.

Local models may be less reliable for tiny text, dense labels, exact values, and strict structured extraction. Review low-confidence results.

Free text — whatever you installed. A suggestion, not a fixed list.

Only a model on this computer is accepted.

1 is the safe default. 3–4 need plenty of memory.

Stopping a long local run

A model on this computer costs nothing to run but can take hours. Set either of these to stop a run before it gets there. Zero means no limit.

Your cap on what a service can charge

Applies only to a service you have an account with. A model on this computer has no provider charge. The cap is checked before anything is sent, so the amount that would cross it is never spent.

US dollars, per job. Estimated from local pricing assumptions, not fetched from anyone.

{% if health %}
What the check found
{% if health.runtime_version %} {% endif %} {% if health.model_available is not none %} {% endif %}
Local model check results
Is anything answering on this computer? {{ "Yes" if health.reachable else "No" }}
Version{{ health.runtime_version }}
Is the model installed? {{ "Found" if health.model_available else "Not installed" }}
Can it read pictures?{{ health.vision_status_label }}

{{ health.detail }}

{% if health.remediation %}
{{ health.remediation }}
{% endif %} {% if health.advisory %}

{{ health.advisory }}

{% endif %}
{% endif %}
Services you have an account with

Only the numbered still pictures are sent — never your video and never its audio. You see what will be sent and roughly what it costs before anything leaves this computer, and sending stops at your cap.

{# The order matters and is not guessable: Check reads the *stored* key, so a key that has been typed but not saved gets a refusal that reads like a bad key. Saying the sequence once, here, is cheaper than explaining it in each row's error. #}

Save a key first. Then press Check, and that service will be asked which models it offers — the Model box fills with real names to choose from. You can also type a model name yourself if you already know it.

{% for entry in credentials %}
{# The name falls back to a locally-derived one. Templates are re-read from disk on every request while route code stays in memory, so a server started before `label` was added renders this file against a context that has none — and every service then appeared as an unnamed grey box reading only "No key set.", which is exactly the state this heading exists to prevent. A screen must not depend on the route being the same age as the template. #}
{{ entry.label | default( {'anthropic': 'Claude', 'google': 'Google', 'openai': 'OpenAI', 'openai_compatible': 'Another service (OpenAI format)', 'anthropic_compatible': 'Another service (Claude format)'}.get( entry.provider, entry.provider), true) }} {# The tag and the sentence used to say the same thing twice — "No key set" above "No key set." The detail sentence carries strictly more information, so the tag only appears when it adds something. #} {% if entry.status.present %} Key set {% endif %} {{ entry.status.detail }}
{# Write-only. A stored key is never rendered back, not even masked: a few revealed characters still narrow a search, and presence is the only fact this screen needs to show. #}
{% if entry.status.present %}
{% endif %} {# Model and address sit with the service they belong to. This used to be a single model box for the whole application, so choosing Claude and then switching to Gemini asked Google for a Claude model. "Check" asks the service what it offers. Deliberately a button rather than something that happens on load: it is a call to another company's computer, and it should happen because you asked. It sends no picture and no video, and a service that answers with a catalogue is one your key works against — so it doubles as the key check. #}
{% if entry.needs_address %}
{% endif %}
{# The placeholder is the next step, not a description of emptiness. "Not chosen yet" restates what an empty box already shows; the useful thing to say is what would fill it. #} {# Populated by Check. Free text either way: a fixed catalogue would be wrong the week a service renames something. #}
{% endfor %}

{# Say what is true here, not both possibilities. Enumerating them made a reader on a Mac — where the Keychain is always available — conclude they would be retyping keys every session. The "session only" half is real, but only on a machine with no secure store: a headless Linux box, a container, an SSH session with no keyring daemon. #} {% if secure_store %} Keys are kept in this computer's secure store and stay there until you remove them. They are never written to a file, never shown back, and never included in any output or collection. {% else %} This computer has no secure store available, so a key can only be read from the environment and lasts for this session. To keep one, set the service's environment variable before starting. Keys are never written to a file, never shown back, and never included in any output or collection. {% endif %}

Where things are kept

{# Repointing moves nothing, and says so. Relocating a tree that can run to tens of gigabytes with a live database inside it is a different feature with its own failure modes; quietly half-doing it would be the worst of the options. #} Work already done stays exactly where it is. Changing this only decides where new jobs are written.

{% if root_blocker %}

{{ root_blocker }}

{% endif %}

Takes effect the next time you start it — the address in your browser does not change until then.

{% if draft.port != running_port %}

Saved as {{ draft.port }}. This server is still answering on {{ running_port }} until it is stopped and started again.

{% endif %}
Reachable at
{{ settings.base_url }}

Turning speech into text

Runs on your processor. Nothing is sent anywhere, and the original timeline is always preserved — silences are marked rather than removed.

Larger is more accurate and slower. medium is the default.

auto works it out from the audio. Naming it is faster and more reliable when you know it.

Seconds. Gaps at least this long are marked in the transcript.

auto picks what is installed.

Collections

What a new collection starts with. Every one of these can still be changed on the collection itself.

Off is the safer default: a model reading half a video with no sign that it is half will summarise it as though it were whole.

Telling you when a job finishes

Jobs here run for hours while you do something else. All of this happens on this computer — there is no push service, no email, and nothing is sent anywhere.

Two things are always on and need no permission: the tab title shows a count when something finishes, and any job that finished while you were away is listed at the top of the screen until you dismiss it.

Your browser will ask for permission when you tick this, not before. It only works while a tab is open.

For when you started this from a terminal and switched away.

Advanced

Sensible defaults already. Worth changing only if something is going wrong, or if you know why you want to.

Pictures, by default

Each job chooses its own when you start it. This is only what it starts on.

Background processing
A model on this computer

1 is the safe default. More needs plenty of memory.

{% endblock %} {% block scripts %} {% endblock %}