You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 28793d8
Browse filesBrowse the repository at this point in the historyBrowse files
Fix caption corrections, model downloads and missing-model jobs (#163)
* Model downloads count as done only when the model is installed (#148, #150)
A pull now counts as done only once Ollama has sent "success" and lists the
model. A stream that stops short, or a model that never shows up, is reported
as an error, so a failed tag is never chosen as the active model (that gave a
404 from /api/generate). Each download's state is kept for the new
GET /models/pulls, and a second POST /models/pull for a tag that is already
downloading starts nothing and returns "already".
The Models page tracks each download by tag. It reads GET /models/pulls when it
opens and every 3 s while something downloads, so a missed final event no longer
leaves the bar stuck. The percentage rounds down and stops at 99 until the model
is done. Ollama's checking steps say to keep the app open, and a failure shows
its error with Try again. Setup does the same, starts its download by itself
only once, and offers Try again after an error or when "done" still leaves no
usable model.
The bundled Ollama runs with OLLAMA_NOPRUNE so a stopped download resumes
instead of being pruned at the next start. Its output goes to
<data>/logs/ollama.log. Closing the app while a model downloads asks first. It
asks the engine, and if the engine doesn't answer within 2 s it quits anyway.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* A missing local model fails the job at once, in plain words (#149)
A job on a local model that was never downloaded ran the download and the
transcription, then failed with "404 Client Error: Not Found for url:
http://127.0.0.1:11435/api/generate".
- OllamaBackend: a 4xx is no longer a bare HTTPError. A 404 raises
LLMError("model_unavailable"): the model isn't downloaded, get it on the
Models page. Any other refusal says what Ollama said. Still asked once.
- The worker asks Ollama what it has before a process job downloads
anything, and ends the job when there is no model at all. Ollama not
answering, another installed model, a cloud model and a Shorts-only
plugin pipeline run as before.
- A failed job stores an LLMError's own message.
- resolve_usable_model returns the name Ollama listed ("gemma3:12b"), never
a bare family that Ollama reads as gemma3:latest and answers with a 404.
- The queue row offers Open Models for this error, beside the OpenRouter
suggestion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Editor: a fixed caption word is burned and shown after Apply (#147)
A corrected word could reach the render with its old spelling, and the
editor kept showing the old text after Apply:
- Caption fixes and mute censoring move to lib/captionEdits.ts and match
words by Unicode letters, marks and digits instead of \b, which knows
only a-z: an accented word was never found, and "perch" matched inside
"perché".
- The word box keeps what was typed when it loses focus, like Enter;
only Escape drops it.
- Apply leaves the draft preview for the clip.
- A re-render deletes the old draft and publishes clip_replaced, and the
clip list moves the open editor and the selected card to the new id
instead of losing the clip.
- /media and /media/preview send Cache-Control: no-store, and the preview
route's leftover unlink uses core.paths.discard (WinError 32).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* llm/pulls.py: which model downloads are running in this process
Shared by the model download (server/api.py) and the job's model check
(server/jobs.py), so a job doesn't fail for a model still downloading.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Model downloads: every quit asks, a cut-off pull says try again, old partials go
A pull whose stream Ollama cut off (it quit or crashed while checking, or the
connection dropped) made requests raise from iter_lines, so the error was
"Response ended prematurely". It now gets the same plain "didn't finish (last
step: ...). Try again" message. The download is recorded in llm.pulls from
before its thread starts until it ends, so a job can tell its model is coming.
The quit warning moves into before-quit, so File > Exit, the tray and the
window all ask; the updater's install and session end go straight through, and
an engine that doesn't answer in 2 s never holds a quit up. Its text now says
what happens: start it again from the Models page and it carries on.
OLLAMA_NOPRUNE stays, but partial blobs untouched for a week are deleted
before Ollama starts. Setup stops waiting on a download the engine has
forgotten, and the Ask Clips Kitty install button uses the shared percentage
and checking text and catches up from GET /models/pulls.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* The job-start model check runs first and lets a model on its way through
Review of the #149 check:
- A process job is checked before it waits for its own prefetch or starts
the next video's. A job failing the check used to start that download,
so a batch with no model downloaded every video only to fail each one.
Render and translate jobs start the prefetch as before.
- The check lets the job go ahead while a model download is running in
this process (llm/pulls.py), as the first-run flow needs: setup tells a
new user to carry on, and Ollama lists nothing until the pull is done.
- It also lets through a Shorts job whose Shorts were made before (no
force): process_video ends it as done without the AI, as it always did.
- The queue row's Open Models matches missing_model's own wording, not a
plugin's model that "isn't downloaded yet" (Marketplace, not Models).
- A bare family takes its smallest recommended member, not whichever
Ollama lists first (the most recently pulled).
- Preflight names the model a job will load ("gemma3:12b", not "gemma3").
- The AI stack repo map describes installed_as, usable_model_in and the
job-start check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Editor: a word with a hyphen is fixed, and the editor stays open after Apply (#147)
The review of the caption fixes found gaps left in them:
- captionEdits.ts trims punctuation only from a word's ends. Taken out of
the middle too, "peut-être", "e-mail", "3,5", "U.S." and a Persian word
with a ZWNJ inside were never found in the caption line, so their fix
or mute went nowhere.
- ClipStudio notes a re-rendered clip's new id as clip_replaced comes,
and every refresh moves the editor and the selected card with the list
that has it. The job's own 'done' refresh could land first, and the
editor closed and opened again from scratch.
- Escape in the word box drops that word only; EditorModal no longer
closes the editor on an Escape typed in a text field.
- test_clip_rekey keeps a real second clip's draft, not the new clip's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #147-#150: the last review findings
- llm/pulls.py counts downloads, so a retry of the same tag starting as the
first one's thread ends isn't taken off the list.
- The updater's "installing" flag is set on before-quit-for-update, when the
installer really starts; set on the click, a failed install left every later
quit skipping the download question.
- Closing the window with nothing watched drops the tray before quitting, so
the download question shows the window instead of leaving it hidden.
- dropStalePartials also clears finished blobs no manifest lists after a week
(what a quit during "verifying" leaves), and only when every manifest reads.
- A corrected caption word no longer doubles the line's punctuation ("ciao,,").
- Escape from a slider or a checkbox leaves the editor again; only text fields
count as typing.
- The AI-stack map's line references, a tighter family test, and CHANGELOG
entries for #147 and #149.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #147-#150: final review fixes
- The job-start model check lets an Edited Stream through: it only cuts
silence and AFK stretches with a fixed title, and finished with no model
before the check. Its "also make Shorts" still needs one, unless they were
made before.
- dropStalePartials deletes no whole blob unless every manifest is the bundled
Ollama's own shape (docker v2 manifest, a config, no manifest list) and there
is no manifests-v2 folder: a newer Ollama's models would read as orphans. A
test pins the bundled Ollama at v0.32.6 so a bump brings a look at this file.
- A word both corrected and muted is censored as corrected; the mute looked
for Whisper's spelling, which the fix had already replaced.
- The job log no longer says a family in settings "is not installed" when
Ollama has it as :latest, or loads a member of it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: ColinGPT9 <ColinGPT9@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/developers/api-reference.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
API version **1** (`GET /health` → `api_version`). The engine listens on `http://127.0.0.1:8765`. How to call it, with examples and the gotchas, is in [`docs/API.md`](../API.md); what the labels promise is in [API](api.md).
-`installed_models(host) -> [{"name","size_gb"}]` = GET `{host}/api/tags` (`:136-143`).
72
-
-`model_is_installed(tag, installed)` matches `"gemma:7b"`, `"ollama/gemma:7b"` or family (`:146-156`).
73
-
-`resolve_usable_model(host, configured) -> str | None` (`:159-189`): configured if installed, else first RECOMMENDATIONS tag installed, else `installed[0]`.
74
-
-`switch_model(settings_path, model_tag) -> str` rewrites the `model:` line in settings.yaml via regex (`:192-202`).
71
+
-`installed_models(host, timeout=15) -> [{"name","size_gb"}]` = GET `{host}/api/tags` (`:138-145`).
72
+
-`model_is_installed(tag, installed)` matches `"gemma:7b"`, `"ollama/gemma:7b"` or family (`:148-154`); it is `installed_as(...) is not None`.
73
+
-`installed_as(tag, installed) -> str | None` (`:157-180`): the name Ollama lists `tag` under, never a bare family (Ollama reads `"gemma3"` as `gemma3:latest` and answers 404 when only `gemma3:12b` was pulled, #149): the exact name, then `<family>:latest`, then the family member that comes first in RECOMMENDATIONS (smallest first, so the result doesn't depend on Ollama listing the most recently pulled first), then the family's first in Ollama's order.
74
+
-`missing_model(model) -> LLMError("model_unavailable", "The AI model <model> isn't downloaded. Download it on the Models page, or choose a model you have.")` (`:183-192`); `OllamaBackend` raises it on a 404, and the queue row's `MODEL_NOT_DOWNLOADED` (`ui/src/renderer/src/components/queue/QueueItem.tsx`) matches its wording to offer Open Models.
75
+
-`resolve_usable_model(host, configured) -> str | None` (`:195-213`) asks Ollama, then `usable_model_in(configured, installed)` (`:216-233`) answers from the list: `installed_as(configured)` if installed, else the first RECOMMENDATIONS tag installed, else `installed[0]`; None only for an empty list (or, for `resolve_usable_model`, Ollama not answering). The name returned is always one Ollama listed.
76
+
-`switch_model(settings_path, model_tag) -> str` rewrites the `model:` line in settings.yaml via regex (`:236-246`).
75
77
76
78
Ollama HTTP calls used across the engine: `GET /api/tags` (`llm/manager.py:138`, `core/preflight.py:101`), `POST /api/generate` (`llm/ollama_backend.py:110`), `POST /api/show` (`llm/ollama_backend.py:167`), `POST /api/pull` streamed with `{"model": tag}` (`server/api.py:2862-2863`), `DELETE /api/delete` (`server/api.py:2922`).
`/models` endpoints (`server/api.py:2933-3141`): `GET /models` -> `{active, installed, recommendations, other_models, recommended: recommend_for(_nvidia_vram_gb())}`; `POST /models/activate {tag}` (must be pulled; `switch_model`); `POST /models/pull {tag}` (background thread, broadcasts `{"type":"model_pull", tag, status, completed, total}` events; "done" only once Ollama said `success` and `/api/tags` lists the tag, then `_select_if_nothing_usable`; a cut-off stream is an "error" saying to try again; a second call for a tag still downloading returns `already: true`; the running tags are in `llm/pulls.py` for the job check); `GET /models/pulls` (each download's last state, so the UI catches up after a missed event); `DELETE /models/{tag}`. CLI: `python main.py models [use <tag>]` (`main.py:186-188`, `:339-383`). UI: `ui/src/renderer/src/lib/api.ts:460,523,525`, `ui/src/renderer/src/pages/Models.tsx`.
79
81
80
82
Where Ollama keeps its models: in a checkout, whatever the system Ollama uses (not managed by the repo). Packaged desktop app: Electron spawns the bundled `ollama serve` on port 11435 with env `OLLAMA_HOST` and `OLLAMA_MODELS: models` (`ui/src/main/index.ts:25-29`, `:161-163`) and tells the engine via `CLIPS_STUDIO_OLLAMA_HOST` (`:219`). `models` = `%LOCALAPPDATA%/Clips Kitty/data/models` if it already holds a `manifests/` folder (1.1.3/1.1.4 installs), else `%LOCALAPPDATA%/Clips Studio/data/models` (`ui/src/main/index.ts:150-159`), i.e. inside the engine's data dir from `core/paths.resolve_data_dir` (`core/paths.py:45-46`). The bundled exe is `resources/backend/_internal/ollama/ollama.exe` (`ui/src/main/index.ts:144`).
Preflight (`core/preflight.py:298-331 run(config)`): `check_ffmpeg`, `check_ollama(host, model)` (GET /api/tags + `resolve_usable_model`), `check_cloud_ai`, `check_cloud_transcription`, `check_whisper(configured)` (non-blocking: "faster-whisper can still fetch them from Hugging Face", `:200-204`), `check_gpu`, `check_disk`.
120
+
Job-start check (`server/jobs.py:692-736 Worker._check_local_model(db, vid, llm_cfg, payload)`): for a process job on a local backend, before this video's prefetch is waited on or the next one's started, the worker asks Ollama (GET /api/tags, 5 s timeout) and raises `missing_model` only when `usable_model_in` finds nothing at all. It lets the job run when Ollama doesn't answer, when another model is installed (`_with_usable_model` swaps it in later), when a model download is in flight in this process (`llm/pulls.py running()`; Ollama lists a model only once its pull is complete), for a Shorts-only plugin pipeline, and for a Shorts job whose Shorts were made before (`db.shorts_made`) without `force`.
121
+
122
+
Preflight (`core/preflight.py:298-331 run(config)`): `check_ffmpeg`, `check_ollama(host, model)` (GET /api/tags + `usable_model_in` on that list, reporting the name a job will load), `check_cloud_ai`, `check_cloud_transcription`, `check_whisper(configured)` (non-blocking: "faster-whisper can still fetch them from Hugging Face", `:200-204`), `check_gpu`, `check_disk`.
119
123
120
124
## 6. What a shared model manager would have to index, and what already exists
0 commit comments