Resolve merge conflict: keep unified search, drop simpler kiwix_search
Main added a basic kiwix_search tool. Our branch already has a unified search() that does everything kiwix_search did plus: DDG fallback, freshness detection, structured results, and read_doc() for full articles. Keep our version, keep the sync tool from our branch. https://claude.ai/code/session_01PtYTPherSJaxDEVPgF6Nxu
This commit is contained in:
+23
-3
@@ -86,10 +86,22 @@ WIKNEWS=$(latest_zim "$MIRROR/wikinews" "wikinews_en_all_nopic")
|
|||||||
inf "Checking Vikidia (kids K-8)..."
|
inf "Checking Vikidia (kids K-8)..."
|
||||||
VIKIDIA=$(latest_zim "$MIRROR/vikidia" "vikidia_en_all_nopic")
|
VIKIDIA=$(latest_zim "$MIRROR/vikidia" "vikidia_en_all_nopic")
|
||||||
|
|
||||||
# Stack Overflow: domain-style filename in stack_exchange/
|
# Stack Exchange sites: domain-style filenames in stack_exchange/
|
||||||
inf "Checking Stack Overflow..."
|
inf "Checking Stack Overflow..."
|
||||||
SO=$(latest_zim "$MIRROR/stack_exchange" "stackoverflow.com_en_all")
|
SO=$(latest_zim "$MIRROR/stack_exchange" "stackoverflow.com_en_all")
|
||||||
|
|
||||||
|
inf "Checking Ask Ubuntu..."
|
||||||
|
ASKUBUNTU=$(latest_zim "$MIRROR/stack_exchange" "askubuntu.com_en_all")
|
||||||
|
|
||||||
|
inf "Checking Super User..."
|
||||||
|
SUPERUSER=$(latest_zim "$MIRROR/stack_exchange" "superuser.com_en_all")
|
||||||
|
|
||||||
|
inf "Checking Unix & Linux SE..."
|
||||||
|
UNIX=$(latest_zim "$MIRROR/stack_exchange" "unix.stackexchange.com_en_all")
|
||||||
|
|
||||||
|
inf "Checking Server Fault..."
|
||||||
|
SERVERFAULT=$(latest_zim "$MIRROR/stack_exchange" "serverfault.com_en_all")
|
||||||
|
|
||||||
# Arch Wiki: _maxi is part of the base name, not the date stamp
|
# Arch Wiki: _maxi is part of the base name, not the date stamp
|
||||||
inf "Checking Arch Wiki..."
|
inf "Checking Arch Wiki..."
|
||||||
ARCH=$(latest_zim "$MIRROR/other" "archlinux_en_all_maxi")
|
ARCH=$(latest_zim "$MIRROR/other" "archlinux_en_all_maxi")
|
||||||
@@ -135,6 +147,10 @@ echo " Wikiversity ${WIKUNI:-NOT FOUND} ~500MB"
|
|||||||
echo " WikiNews ${WIKNEWS:-NOT FOUND} ~300MB"
|
echo " WikiNews ${WIKNEWS:-NOT FOUND} ~300MB"
|
||||||
echo " Vikidia (kids K-8) ${VIKIDIA:-NOT FOUND} ~66MB"
|
echo " Vikidia (kids K-8) ${VIKIDIA:-NOT FOUND} ~66MB"
|
||||||
echo " Stack Overflow ${SO:-NOT FOUND} ~3GB"
|
echo " Stack Overflow ${SO:-NOT FOUND} ~3GB"
|
||||||
|
echo " Ask Ubuntu ${ASKUBUNTU:-NOT FOUND} ~1GB"
|
||||||
|
echo " Super User ${SUPERUSER:-NOT FOUND} ~1GB"
|
||||||
|
echo " Unix & Linux SE ${UNIX:-NOT FOUND} ~500MB"
|
||||||
|
echo " Server Fault ${SERVERFAULT:-NOT FOUND} ~500MB"
|
||||||
echo " Arch Linux Wiki ${ARCH:-NOT FOUND} ~30MB"
|
echo " Arch Linux Wiki ${ARCH:-NOT FOUND} ~30MB"
|
||||||
echo " TED Talks ${TED:-NOT FOUND} ~5GB"
|
echo " TED Talks ${TED:-NOT FOUND} ~5GB"
|
||||||
echo " PhET Simulations ${PHET:-NOT FOUND} ~500MB"
|
echo " PhET Simulations ${PHET:-NOT FOUND} ~500MB"
|
||||||
@@ -144,7 +160,7 @@ echo " iFixit (repair guides) ${IFIX:-NOT FOUND} ~2GB"
|
|||||||
echo " LibreTexts (textbooks) ${LIBRE:-NOT FOUND} ~varies"
|
echo " LibreTexts (textbooks) ${LIBRE:-NOT FOUND} ~varies"
|
||||||
echo " Project Gutenberg ${GUT:-NOT FOUND} ~60GB"
|
echo " Project Gutenberg ${GUT:-NOT FOUND} ~60GB"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${Y} Total estimate: ~130GB — make sure you have space!${N}"
|
echo -e "${Y} Total estimate: ~133GB — make sure you have space!${N}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
df -h "$KIWIX_DIR" | tail -1 | awk '{print " Available disk space: " $4}'
|
df -h "$KIWIX_DIR" | tail -1 | awk '{print " Available disk space: " $4}'
|
||||||
@@ -166,7 +182,11 @@ rm -f "$KIWIX_DIR/.download_pids"
|
|||||||
[[ -n "$WIKUNI" ]] && download_zim "wikiversity" "$WIKUNI" "Wikiversity" "500MB"
|
[[ -n "$WIKUNI" ]] && download_zim "wikiversity" "$WIKUNI" "Wikiversity" "500MB"
|
||||||
[[ -n "$WIKNEWS" ]] && download_zim "wikinews" "$WIKNEWS" "WikiNews" "300MB"
|
[[ -n "$WIKNEWS" ]] && download_zim "wikinews" "$WIKNEWS" "WikiNews" "300MB"
|
||||||
[[ -n "$VIKIDIA" ]] && download_zim "vikidia" "$VIKIDIA" "Vikidia (kids K-8)" "66MB"
|
[[ -n "$VIKIDIA" ]] && download_zim "vikidia" "$VIKIDIA" "Vikidia (kids K-8)" "66MB"
|
||||||
[[ -n "$SO" ]] && download_zim "stack_exchange" "$SO" "Stack Overflow" "3GB"
|
[[ -n "$SO" ]] && download_zim "stack_exchange" "$SO" "Stack Overflow" "3GB"
|
||||||
|
[[ -n "$ASKUBUNTU" ]] && download_zim "stack_exchange" "$ASKUBUNTU" "Ask Ubuntu" "1GB"
|
||||||
|
[[ -n "$SUPERUSER" ]] && download_zim "stack_exchange" "$SUPERUSER" "Super User" "1GB"
|
||||||
|
[[ -n "$UNIX" ]] && download_zim "stack_exchange" "$UNIX" "Unix & Linux SE" "500MB"
|
||||||
|
[[ -n "$SERVERFAULT" ]] && download_zim "stack_exchange" "$SERVERFAULT" "Server Fault" "500MB"
|
||||||
[[ -n "$ARCH" ]] && download_zim "other" "$ARCH" "Arch Linux Wiki" "30MB"
|
[[ -n "$ARCH" ]] && download_zim "other" "$ARCH" "Arch Linux Wiki" "30MB"
|
||||||
[[ -n "$TED" ]] && download_zim "ted" "$TED" "TED Talks" "5GB"
|
[[ -n "$TED" ]] && download_zim "ted" "$TED" "TED Talks" "5GB"
|
||||||
[[ -n "$PHET" ]] && download_zim "phet" "$PHET" "PhET Simulations" "500MB"
|
[[ -n "$PHET" ]] && download_zim "phet" "$PHET" "PhET Simulations" "500MB"
|
||||||
|
|||||||
Executable
+130
@@ -0,0 +1,130 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# =============================================================================
|
||||||
|
# Kiwix ZIM Auto-Updater
|
||||||
|
# Checks each ZIM for a newer version on the mirror, downloads it, removes old.
|
||||||
|
# Safe to run as a cron job — only acts when a newer version exists.
|
||||||
|
# Usage: bash kiwix_update.sh
|
||||||
|
# Cron example (monthly): 0 3 1 * * /bin/bash /path/to/kiwix_update.sh
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
KIWIX_DIR="$HOME/docker/ai-stack/kiwix"
|
||||||
|
MIRROR="https://ftp.fau.de/kiwix/zim"
|
||||||
|
MIRROR2="https://download.kiwix.org/zim"
|
||||||
|
LOG="$HOME/docker/ai-stack/logs/kiwix-update.log"
|
||||||
|
mkdir -p "$KIWIX_DIR" "$(dirname "$LOG")"
|
||||||
|
|
||||||
|
G='\033[0;32m'; Y='\033[1;33m'; C='\033[0;36m'; R='\033[0;31m'; N='\033[0m'
|
||||||
|
ok() { echo -e "${G}[OK]${N} $1" | tee -a "$LOG"; }
|
||||||
|
inf() { echo -e "${C}[..]${N} $1" | tee -a "$LOG"; }
|
||||||
|
wrn() { echo -e "${Y}[!!]${N} $1" | tee -a "$LOG"; }
|
||||||
|
err() { echo -e "${R}[XX]${N} $1" | tee -a "$LOG"; }
|
||||||
|
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
|
echo "=== Kiwix Update Check: $(date) ===" | tee -a "$LOG"
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
|
|
||||||
|
# Find latest filename on mirror
|
||||||
|
latest_zim() {
|
||||||
|
local base_url="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
curl -s "$base_url/" | \
|
||||||
|
grep -oP "${pattern}_[\d-]+\.zim" | \
|
||||||
|
sort -u | tail -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find what's currently on disk matching a pattern
|
||||||
|
current_zim() {
|
||||||
|
local pattern="$1"
|
||||||
|
ls "$KIWIX_DIR"/${pattern}_*.zim 2>/dev/null | sort | tail -1 | xargs basename 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check and update one ZIM
|
||||||
|
# Usage: check_update "category" "pattern" "description" ["mirror"]
|
||||||
|
UPDATED=0
|
||||||
|
check_update() {
|
||||||
|
local category="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
local description="$3"
|
||||||
|
local mirror="${4:-$MIRROR}"
|
||||||
|
|
||||||
|
inf "Checking $description..."
|
||||||
|
local latest
|
||||||
|
latest=$(latest_zim "$mirror/$category" "$pattern")
|
||||||
|
|
||||||
|
if [[ -z "$latest" ]]; then
|
||||||
|
wrn "$description: could not find latest on mirror — skipping"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local current
|
||||||
|
current=$(current_zim "$pattern")
|
||||||
|
|
||||||
|
if [[ -z "$current" ]]; then
|
||||||
|
inf "$description: not downloaded yet — skipping (run kiwix_download.sh first)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$latest" == "$current" ]]; then
|
||||||
|
ok "$description: up to date ($current)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
inf "$description: update available"
|
||||||
|
inf " Current: $current"
|
||||||
|
inf " Latest: $latest"
|
||||||
|
|
||||||
|
local url="$mirror/$category/$latest"
|
||||||
|
local dest="$KIWIX_DIR/$latest"
|
||||||
|
local old="$KIWIX_DIR/$current"
|
||||||
|
|
||||||
|
inf " Downloading $latest..."
|
||||||
|
if wget -q --show-progress -c "$url" -O "$dest" >> "$LOG" 2>&1; then
|
||||||
|
ok " Download complete — removing old file"
|
||||||
|
rm -f "$old"
|
||||||
|
UPDATED=$((UPDATED + 1))
|
||||||
|
else
|
||||||
|
err " Download failed — keeping old file"
|
||||||
|
rm -f "$dest"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Check each ZIM ─────────────────────────────────────────────────────────
|
||||||
|
check_update "wikipedia" "wikipedia_en_all_nopic" "Wikipedia"
|
||||||
|
check_update "wiktionary" "wiktionary_en_all_nopic" "Wiktionary"
|
||||||
|
check_update "wikiquote" "wikiquote_en_all_nopic" "Wikiquote"
|
||||||
|
check_update "wikisource" "wikisource_en_all_nopic" "Wikisource"
|
||||||
|
check_update "wikibooks" "wikibooks_en_all_nopic" "Wikibooks"
|
||||||
|
check_update "wikivoyage" "wikivoyage_en_all_nopic" "Wikivoyage"
|
||||||
|
check_update "wikiversity" "wikiversity_en_all_nopic" "Wikiversity"
|
||||||
|
check_update "wikinews" "wikinews_en_all_nopic" "WikiNews"
|
||||||
|
check_update "vikidia" "vikidia_en_all_nopic" "Vikidia"
|
||||||
|
check_update "stack_exchange" "stackoverflow.com_en_all" "Stack Overflow"
|
||||||
|
check_update "stack_exchange" "askubuntu.com_en_all" "Ask Ubuntu"
|
||||||
|
check_update "stack_exchange" "superuser.com_en_all" "Super User"
|
||||||
|
check_update "stack_exchange" "unix.stackexchange.com_en_all" "Unix & Linux SE"
|
||||||
|
check_update "stack_exchange" "serverfault.com_en_all" "Server Fault"
|
||||||
|
check_update "other" "archlinux_en_all_maxi" "Arch Wiki"
|
||||||
|
check_update "ted" "ted_mul_youth" "TED Talks"
|
||||||
|
check_update "phet" "phet_en_all" "PhET Simulations"
|
||||||
|
check_update "devdocs" "devdocs_en_zig" "DevDocs"
|
||||||
|
check_update "freecodecamp" "freecodecamp_en_all" "FreeCodeCamp"
|
||||||
|
check_update "ifixit" "ifixit_en_all" "iFixit"
|
||||||
|
check_update "libretexts" "libretexts.org_en_workforce" "LibreTexts"
|
||||||
|
check_update "gutenberg" "gutenberg_en_all" "Project Gutenberg" "$MIRROR2"
|
||||||
|
|
||||||
|
# ── Restart Kiwix if anything changed ─────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
if [[ $UPDATED -gt 0 ]]; then
|
||||||
|
ok "$UPDATED ZIM(s) updated — restarting Kiwix container"
|
||||||
|
docker compose -f "$HOME/docker/ai-stack/docker-compose.yml" restart kiwix >> "$LOG" 2>&1 \
|
||||||
|
&& ok "Kiwix restarted" \
|
||||||
|
|| wrn "Could not restart Kiwix — do it manually: docker compose restart kiwix"
|
||||||
|
else
|
||||||
|
ok "All ZIMs are up to date — no restart needed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Update check complete: $(date) ===" | tee -a "$LOG"
|
||||||
|
echo ""
|
||||||
+62
-3
@@ -527,7 +527,7 @@ cat > "$BASE/docker-compose.yml" << COMPOSE
|
|||||||
# Pull latest images: docker compose pull && docker compose up -d
|
# Pull latest images: docker compose pull && docker compose up -d
|
||||||
# Show status: docker compose ps
|
# Show status: docker compose ps
|
||||||
#
|
#
|
||||||
# Services: ollama open-webui chromadb rag-server mcp-server
|
# Services: ollama open-webui chromadb rag-server mcp-server aider
|
||||||
# kiwix gitea invokeai portainer
|
# kiwix gitea invokeai portainer
|
||||||
# ───────────────────────────────────────────────────────────────────────────────
|
# ───────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -636,7 +636,28 @@ services:
|
|||||||
bash -c "apt-get update -qq && apt-get install -y --no-install-recommends git ripgrep curl &&
|
bash -c "apt-get update -qq && apt-get install -y --no-install-recommends git ripgrep curl &&
|
||||||
pip install --no-cache-dir -r mcp_requirements.txt &&
|
pip install --no-cache-dir -r mcp_requirements.txt &&
|
||||||
python mcp_server.py"
|
python mcp_server.py"
|
||||||
depends_on: [rag-server]
|
depends_on: [rag-server, kiwix]
|
||||||
|
|
||||||
|
aider:
|
||||||
|
image: paulgauthier/aider:latest
|
||||||
|
container_name: aider
|
||||||
|
restart: unless-stopped
|
||||||
|
ports: ["0.0.0.0:8080:8501"]
|
||||||
|
volumes:
|
||||||
|
- $BASE/workspace:/workspace
|
||||||
|
- $BASE/repos:/repos
|
||||||
|
working_dir: /workspace
|
||||||
|
environment:
|
||||||
|
- OLLAMA_API_BASE=http://ollama:11434
|
||||||
|
- GIT_AUTHOR_NAME=aider
|
||||||
|
- GIT_AUTHOR_EMAIL=aider@local
|
||||||
|
- GIT_COMMITTER_NAME=aider
|
||||||
|
- GIT_COMMITTER_EMAIL=aider@local
|
||||||
|
command: >
|
||||||
|
--gui --no-auto-commits --no-check-update
|
||||||
|
--model ollama/$CODE_MODEL
|
||||||
|
depends_on:
|
||||||
|
ollama: {condition: service_healthy}
|
||||||
|
|
||||||
kiwix:
|
kiwix:
|
||||||
image: ghcr.io/kiwix/kiwix-serve:latest
|
image: ghcr.io/kiwix/kiwix-serve:latest
|
||||||
@@ -707,7 +728,7 @@ if command -v ufw &>/dev/null && [[ ! -f "$BASE/.ufw-done" ]] || $FORCE; then
|
|||||||
read -rp " LAN subnet [192.168.1.0/24]: " LAN; LAN="${LAN:-192.168.1.0/24}"
|
read -rp " LAN subnet [192.168.1.0/24]: " LAN; LAN="${LAN:-192.168.1.0/24}"
|
||||||
[[ "$LAN" =~ /[0-9]+$ ]] || LAN="${LAN}/24"
|
[[ "$LAN" =~ /[0-9]+$ ]] || LAN="${LAN}/24"
|
||||||
for pc in "3000:Open WebUI" "11434:Ollama" "8001:RAG" "8002:MCP" \
|
for pc in "3000:Open WebUI" "11434:Ollama" "8001:RAG" "8002:MCP" \
|
||||||
"8000:ChromaDB" "8181:Kiwix" \
|
"8000:ChromaDB" "8080:Aider" "8181:Kiwix" \
|
||||||
"3001:Gitea" "2222:Gitea SSH" "9090:InvokeAI" \
|
"3001:Gitea" "2222:Gitea SSH" "9090:InvokeAI" \
|
||||||
"9000:Portainer" "9443:Portainer S"; do
|
"9000:Portainer" "9443:Portainer S"; do
|
||||||
sudo ufw allow from "$LAN" to any port "${pc%%:*}" proto tcp comment "${pc##*:}" >/dev/null
|
sudo ufw allow from "$LAN" to any port "${pc%%:*}" proto tcp comment "${pc##*:}" >/dev/null
|
||||||
@@ -725,6 +746,7 @@ docker compose pull --quiet 2>/dev/null
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
echo ""
|
echo ""
|
||||||
echo " Open WebUI → http://$LOCAL_IP:3000"
|
echo " Open WebUI → http://$LOCAL_IP:3000"
|
||||||
|
echo " Aider UI → http://$LOCAL_IP:8080 (Claude Code-like editor)"
|
||||||
echo " InvokeAI → http://$LOCAL_IP:9090"
|
echo " InvokeAI → http://$LOCAL_IP:9090"
|
||||||
echo " Kiwix → http://$LOCAL_IP:8181 (run kiwix_download.sh first)"
|
echo " Kiwix → http://$LOCAL_IP:8181 (run kiwix_download.sh first)"
|
||||||
echo " Gitea → http://$LOCAL_IP:3001"
|
echo " Gitea → http://$LOCAL_IP:3001"
|
||||||
@@ -778,6 +800,39 @@ PULLSH
|
|||||||
chmod +x "$BASE/pull-models.sh"
|
chmod +x "$BASE/pull-models.sh"
|
||||||
ok "start.sh stop.sh status.sh pull-models.sh"
|
ok "start.sh stop.sh status.sh pull-models.sh"
|
||||||
|
|
||||||
|
cat > "$BASE/aider.sh" << AIDSH
|
||||||
|
#!/bin/bash
|
||||||
|
# Aider CLI — Claude Code-like terminal experience against any local git repo.
|
||||||
|
# Usage:
|
||||||
|
# ./aider.sh # interactive, files from stdin
|
||||||
|
# ./aider.sh src/main.py # open specific files
|
||||||
|
# ./aider.sh --model ollama/qwen2.5-coder:7b src/foo.py # override model
|
||||||
|
#
|
||||||
|
# Tip: clone Gitea repos into $BASE/repos/, then:
|
||||||
|
# cd $BASE/repos/my-project && $BASE/aider.sh <files>
|
||||||
|
|
||||||
|
MODEL="\${AIDER_MODEL:-ollama/$CODE_MODEL}"
|
||||||
|
REPO_ROOT="\$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||||
|
|
||||||
|
docker run --rm -it \\
|
||||||
|
--network local-ai_default \\
|
||||||
|
-v "\$REPO_ROOT:\$REPO_ROOT" \\
|
||||||
|
-v "$BASE/repos:/repos" \\
|
||||||
|
-w "\$REPO_ROOT" \\
|
||||||
|
-e OLLAMA_API_BASE=http://ollama:11434 \\
|
||||||
|
-e GIT_AUTHOR_NAME=aider \\
|
||||||
|
-e GIT_AUTHOR_EMAIL=aider@local \\
|
||||||
|
-e GIT_COMMITTER_NAME=aider \\
|
||||||
|
-e GIT_COMMITTER_EMAIL=aider@local \\
|
||||||
|
paulgauthier/aider:latest \\
|
||||||
|
--no-auto-commits \\
|
||||||
|
--no-check-update \\
|
||||||
|
--model "\$MODEL" \\
|
||||||
|
"\$@"
|
||||||
|
AIDSH
|
||||||
|
chmod +x "$BASE/aider.sh"
|
||||||
|
ok "aider.sh"
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
section "Systemd"
|
section "Systemd"
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -824,6 +879,7 @@ echo -e "${GREEN}${BOLD} Done! GPU: ${VRAM_GB}GB → $TIER${NC}"
|
|||||||
echo -e "${GREEN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
echo -e "${GREEN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${CYAN}Open WebUI${NC} → http://$LOCAL_IP:3000"
|
echo -e " ${CYAN}Open WebUI${NC} → http://$LOCAL_IP:3000"
|
||||||
|
echo -e " ${CYAN}Aider UI${NC} → http://$LOCAL_IP:8080 (browser coding assistant)"
|
||||||
echo -e " ${CYAN}InvokeAI${NC} → http://$LOCAL_IP:9090"
|
echo -e " ${CYAN}InvokeAI${NC} → http://$LOCAL_IP:9090"
|
||||||
echo -e " ${CYAN}Kiwix${NC} → http://$LOCAL_IP:8181"
|
echo -e " ${CYAN}Kiwix${NC} → http://$LOCAL_IP:8181"
|
||||||
echo -e " ${CYAN}Gitea${NC} → http://$LOCAL_IP:3001"
|
echo -e " ${CYAN}Gitea${NC} → http://$LOCAL_IP:3001"
|
||||||
@@ -839,6 +895,9 @@ echo -e " ${YELLOW}PDFs:${NC} $BASE/papers/"
|
|||||||
echo -e " ${YELLOW}Workspace:${NC} $BASE/workspace/"
|
echo -e " ${YELLOW}Workspace:${NC} $BASE/workspace/"
|
||||||
echo -e " ${YELLOW}ZIMs:${NC} ./kiwix_download.sh"
|
echo -e " ${YELLOW}ZIMs:${NC} ./kiwix_download.sh"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo -e " ${YELLOW}Aider CLI:${NC} cd your-repo && $BASE/aider.sh <files>"
|
||||||
|
echo " (or open browser UI above — both use your local code model)"
|
||||||
|
echo ""
|
||||||
echo -e " ${YELLOW}Save Claude usage:${NC} use local 14B for boilerplate, docs,"
|
echo -e " ${YELLOW}Save Claude usage:${NC} use local 14B for boilerplate, docs,"
|
||||||
echo " simple fixes. Use Claude Sonnet 4.6 for hard bugs,"
|
echo " simple fixes. Use Claude Sonnet 4.6 for hard bugs,"
|
||||||
echo " multi-file refactoring, architecture decisions."
|
echo " multi-file refactoring, architecture decisions."
|
||||||
|
|||||||
Executable
+67
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# =============================================================================
|
||||||
|
# Ollama Model Auto-Updater
|
||||||
|
# Pulls latest version of every installed model. Ollama compares digests
|
||||||
|
# server-side — no download happens if the model is already current.
|
||||||
|
# Safe to run as a systemd timer.
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
OLLAMA_URL="${OLLAMA_HOST:-http://localhost:11434}"
|
||||||
|
LOG="$HOME/docker/ai-stack/logs/ollama-update.log"
|
||||||
|
mkdir -p "$(dirname "$LOG")"
|
||||||
|
|
||||||
|
G='\033[0;32m'; Y='\033[1;33m'; C='\033[0;36m'; R='\033[0;31m'; N='\033[0m'
|
||||||
|
ok() { echo -e "${G}[OK]${N} $1" | tee -a "$LOG"; }
|
||||||
|
inf() { echo -e "${C}[..]${N} $1" | tee -a "$LOG"; }
|
||||||
|
wrn() { echo -e "${Y}[!!]${N} $1" | tee -a "$LOG"; }
|
||||||
|
err() { echo -e "${R}[XX]${N} $1" | tee -a "$LOG"; }
|
||||||
|
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
|
echo "=== Ollama Model Update: $(date) ===" | tee -a "$LOG"
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
|
|
||||||
|
# Check Ollama is reachable
|
||||||
|
if ! curl -sf "$OLLAMA_URL/api/tags" > /dev/null; then
|
||||||
|
err "Ollama not reachable at $OLLAMA_URL — is the container running?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get installed model names from the API
|
||||||
|
mapfile -t MODELS < <(
|
||||||
|
curl -sf "$OLLAMA_URL/api/tags" | \
|
||||||
|
grep -oP '"name"\s*:\s*"\K[^"]+' | \
|
||||||
|
sort -u
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ ${#MODELS[@]} -eq 0 ]]; then
|
||||||
|
wrn "No models found — nothing to update"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
inf "Found ${#MODELS[@]} model(s): ${MODELS[*]}"
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
|
|
||||||
|
UPDATED=0
|
||||||
|
FAILED=0
|
||||||
|
|
||||||
|
for model in "${MODELS[@]}"; do
|
||||||
|
inf "Pulling $model..."
|
||||||
|
output=$(ollama pull "$model" 2>&1)
|
||||||
|
exit_code=$?
|
||||||
|
|
||||||
|
if [[ $exit_code -ne 0 ]]; then
|
||||||
|
err "$model: pull failed"
|
||||||
|
echo "$output" >> "$LOG"
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
elif echo "$output" | grep -q "up to date"; then
|
||||||
|
ok "$model: already up to date"
|
||||||
|
else
|
||||||
|
ok "$model: updated"
|
||||||
|
UPDATED=$((UPDATED + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
|
inf "Done — $UPDATED updated, $FAILED failed"
|
||||||
|
echo "=== Complete: $(date) ===" | tee -a "$LOG"
|
||||||
|
echo "" | tee -a "$LOG"
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Install all local-ai systemd user units and enable timers
|
||||||
|
set -e
|
||||||
|
|
||||||
|
UNIT_DIR="$HOME/.config/systemd/user"
|
||||||
|
SRC="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
|
mkdir -p "$UNIT_DIR"
|
||||||
|
|
||||||
|
for unit in "$SRC"/*.service "$SRC"/*.timer; do
|
||||||
|
name=$(basename "$unit")
|
||||||
|
ln -sf "$unit" "$UNIT_DIR/$name"
|
||||||
|
echo "Linked $name"
|
||||||
|
done
|
||||||
|
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
|
||||||
|
for timer in "$SRC"/*.timer; do
|
||||||
|
name=$(basename "$timer")
|
||||||
|
systemctl --user enable --now "$name"
|
||||||
|
echo "Enabled $name"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
systemctl --user list-timers kiwix-update.timer ollama-update.timer
|
||||||
|
echo ""
|
||||||
|
echo "Run manually:"
|
||||||
|
echo " systemctl --user start kiwix-update.service"
|
||||||
|
echo " systemctl --user start ollama-update.service"
|
||||||
|
echo ""
|
||||||
|
echo "Logs:"
|
||||||
|
echo " journalctl --user -u kiwix-update.service -f"
|
||||||
|
echo " journalctl --user -u ollama-update.service -f"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Kiwix ZIM auto-updater
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash %h/local-ai/kiwix_update.sh
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Monthly Kiwix ZIM update check
|
||||||
|
Requires=kiwix-update.service
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=monthly
|
||||||
|
RandomizedDelaySec=1h
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Ollama model auto-updater
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash %h/local-ai/ollama_update.sh
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Monthly Ollama model update check
|
||||||
|
Requires=ollama-update.service
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=monthly
|
||||||
|
RandomizedDelaySec=2h
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
Reference in New Issue
Block a user