feat: playbook tools, RAG, vision, voice, chat controls, faster boot
- Tool-using playbooks: read-only tool registry (search_memory, search_history, search_documents, list_models, get_time), per-playbook allowlist, agentic loop, and a "running tool" status indicator. - Document ingest / RAG: documents table + chunker + embed/cosine retrieval reusing the existing stack; Documents page (upload/paste, viewer, delete); top-k chunks injected into the system prompt. - Vision chat: attach images, base64 into /api/chat. - Voice I/O: Web Speech dictation + read-aloud (browser-native, no backend). - Chat controls: stop, regenerate, edit-and-resend; num_ctx knob in Settings. - Per-playbook model override. - History polish: per-conversation + bulk ShareGPT export. - Faster ncp start: UI up first, Ollama warms in the background, with a per-phase timing readout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+22
-9
@@ -301,20 +301,23 @@ def stop_service(svc: Service) -> bool:
|
||||
|
||||
# -- ollama --------------------------------------------------------------------
|
||||
|
||||
def start_ollama() -> None:
|
||||
def start_ollama(background: bool = False) -> None:
|
||||
"""Driven through the backend endpoint (the path the control panel uses)
|
||||
rather than launching the binary, because OllamaManager owns model and GPU
|
||||
selection. Requires the backend to be up.
|
||||
|
||||
Long timeout: the endpoint blocks until the model is warmed - weights read
|
||||
off disk into RAM/VRAM - which the web UI's own "Loading model..." button
|
||||
state calls out as routinely taking about a minute, not just the Ollama
|
||||
process launching."""
|
||||
background=True (`ncp start`): the endpoint returns as soon as `ollama serve`
|
||||
is up and warms the model in a background task, so boot finishes in seconds
|
||||
and the model loads concurrently into the first chat.
|
||||
background=False (`ncp start --ai`): blocks until the model is warmed - weights
|
||||
read off disk into RAM/VRAM, routinely about a minute - so "started" means the
|
||||
AI can actually answer."""
|
||||
print("Starting OLLAMA...")
|
||||
req = urllib.request.Request("http://localhost:8000/ollama/start", method="POST")
|
||||
url = "http://localhost:8000/ollama/start" + ("?background=true" if background else "")
|
||||
req = urllib.request.Request(url, method="POST")
|
||||
try:
|
||||
urllib.request.urlopen(req, timeout=180).read(1)
|
||||
print("NEXUS OLLAMA STARTED")
|
||||
print("NEXUS OLLAMA WARMING (background)" if background else "NEXUS OLLAMA STARTED")
|
||||
except Exception as e:
|
||||
print(f" OLLAMA start failed: {e}")
|
||||
|
||||
@@ -350,14 +353,24 @@ def cmd_start(target) -> None:
|
||||
elif target in ("--ai", "-a"):
|
||||
start_ollama()
|
||||
elif target in (None, "", "all"):
|
||||
# Memory + backend in parallel, both ready before the frontend starts.
|
||||
# Bring the UI up first, then warm Ollama in the background — the model
|
||||
# loads concurrently and into the first chat instead of blocking boot.
|
||||
t0 = time.perf_counter()
|
||||
launch(SERVICES["memory"])
|
||||
launch(SERVICES["backend"])
|
||||
wait_for_port(SERVICES["memory"])
|
||||
wait_for_port(SERVICES["backend"])
|
||||
start_ollama()
|
||||
t_services = time.perf_counter()
|
||||
launch(SERVICES["frontend"])
|
||||
wait_for_port(SERVICES["frontend"])
|
||||
t_frontend = time.perf_counter()
|
||||
start_ollama(background=True)
|
||||
t_ollama = time.perf_counter()
|
||||
print("\nBoot timing:")
|
||||
print(f" services (memory+backend) : {t_services - t0:5.1f}s")
|
||||
print(f" frontend (UI ready) : {t_frontend - t_services:5.1f}s")
|
||||
print(f" ollama kickoff (bg warm) : {t_ollama - t_frontend:5.1f}s")
|
||||
print(f" total to interactive : {t_ollama - t0:5.1f}s")
|
||||
else:
|
||||
show_help()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user