Merge pull request #11 from outis1one/claude/cleanup-setup-webui-bCgPE
Claude/cleanup setup webui b cg pe
This commit is contained in:
Executable
+211
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env bash
|
||||
# configure-searxng-safesearch.sh
|
||||
# Set SearXNG safe-search level; optionally disable categories or engines.
|
||||
#
|
||||
# Usage:
|
||||
# ./configure-searxng-safesearch.sh [strict|moderate|none] [OPTIONS]
|
||||
#
|
||||
# Options:
|
||||
# --disable-categories cat1,cat2 videos images news science social
|
||||
# --disable-engines eng1,eng2 e.g. duckduckgo,bing,yandex
|
||||
# --enable-engines eng1,eng2 re-enable engines auto-disabled by level
|
||||
#
|
||||
# Examples:
|
||||
# ./configure-searxng-safesearch.sh strict
|
||||
# ./configure-searxng-safesearch.sh moderate --disable-categories videos,images
|
||||
# ./configure-searxng-safesearch.sh none --disable-engines bing,duckduckgo
|
||||
# ./configure-searxng-safesearch.sh strict --disable-categories videos \
|
||||
# --disable-engines bing --enable-engines yandex
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
red() { printf '\e[31m%s\e[0m\n' "$*"; }
|
||||
grn() { printf '\e[32m%s\e[0m\n' "$*"; }
|
||||
blu() { printf '\e[34m%s\e[0m\n' "$*"; }
|
||||
yel() { printf '\e[33m%s\e[0m\n' "$*"; }
|
||||
die() { red "ERROR: $*"; exit 1; }
|
||||
ok() { grn " ✓ $*"; }
|
||||
info() { blu " → $*"; }
|
||||
warn() { yel " ! $*"; }
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────────────
|
||||
LEVEL="moderate"
|
||||
DISABLE_CATS=""
|
||||
DISABLE_ENGINES_EXTRA=""
|
||||
ENABLE_ENGINES_EXTRA=""
|
||||
BASE="${BASE:-$HOME/docker/ai-stack}"
|
||||
|
||||
# ── Parse arguments ───────────────────────────────────────────────────────────
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
strict|moderate|none) LEVEL="$1"; shift ;;
|
||||
--disable-categories) DISABLE_CATS="$2"; shift 2 ;;
|
||||
--disable-engines) DISABLE_ENGINES_EXTRA="$2"; shift 2 ;;
|
||||
--enable-engines) ENABLE_ENGINES_EXTRA="$2"; shift 2 ;;
|
||||
--base) BASE="$2"; shift 2 ;;
|
||||
-h|--help)
|
||||
sed -n '2,20p' "$0" | sed 's/^# \?//'
|
||||
exit 0
|
||||
;;
|
||||
*) die "Unknown argument: $1 (run with --help)" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
SETTINGS="$BASE/searxng/settings.yml"
|
||||
COMPOSE="$BASE/docker-compose.yml"
|
||||
|
||||
# Ensure settings directory exists
|
||||
mkdir -p "$(dirname "$SETTINGS")"
|
||||
|
||||
# ── Level → integer ───────────────────────────────────────────────────────────
|
||||
case "$LEVEL" in
|
||||
none) SAFE_INT=0 ;;
|
||||
moderate) SAFE_INT=1 ;;
|
||||
strict) SAFE_INT=2 ;;
|
||||
esac
|
||||
|
||||
info "Safe search: $LEVEL (${SAFE_INT})"
|
||||
|
||||
# ── Engines with no safe-search support ───────────────────────────────────────
|
||||
# Auto-disabled when level is moderate or strict.
|
||||
NO_SAFESEARCH_ENGINES=(
|
||||
# Torrent / P2P — no filtering possible
|
||||
"1337x" "piratebay" "nyaa" "torrentz" "kickass torrents"
|
||||
# Web engines without safe-search API
|
||||
"mojeek" "naver" "baidu"
|
||||
# Yandex: parameter exists but not reliably enforced for non-Russian queries
|
||||
"yandex"
|
||||
# Video frontends — no safe-search passthrough
|
||||
"invidious" "piped" "peertube" "sepiasearch"
|
||||
)
|
||||
|
||||
# ── Category → engine lists ───────────────────────────────────────────────────
|
||||
VIDEOS_ENGINES=(
|
||||
"youtube" "invidious" "piped" "peertube" "sepiasearch"
|
||||
"dailymotion" "vimeo"
|
||||
"bing videos" "duckduckgo videos" "google videos"
|
||||
)
|
||||
IMAGES_ENGINES=(
|
||||
"google images" "bing images" "duckduckgo images"
|
||||
"brave images" "qwant images"
|
||||
"flickr" "unsplash" "imgur" "deviantart" "openverse"
|
||||
)
|
||||
NEWS_ENGINES=(
|
||||
"google news" "bing news" "duckduckgo news" "brave news" "qwant news"
|
||||
)
|
||||
SCIENCE_ENGINES=(
|
||||
"arxiv" "semantic scholar" "pubmed" "crossref" "base"
|
||||
)
|
||||
SOCIAL_ENGINES=(
|
||||
"reddit" "lemmy" "mastodon"
|
||||
)
|
||||
|
||||
# ── Build disable/enable maps ─────────────────────────────────────────────────
|
||||
declare -A DISABLE_MAP # engine → 1
|
||||
declare -A ENABLE_MAP # engine → 1 (overrides everything)
|
||||
|
||||
# Parse --enable-engines
|
||||
if [[ -n "$ENABLE_ENGINES_EXTRA" ]]; then
|
||||
IFS=',' read -ra _engs <<< "$ENABLE_ENGINES_EXTRA"
|
||||
for e in "${_engs[@]}"; do
|
||||
e="${e#"${e%%[![:space:]]*}"}"; e="${e%"${e##*[![:space:]]}"}" # trim
|
||||
[[ -n "$e" ]] && ENABLE_MAP["$e"]=1
|
||||
done
|
||||
fi
|
||||
|
||||
# Helper: add to DISABLE_MAP unless explicitly re-enabled
|
||||
mark_disabled() {
|
||||
local eng="$1"
|
||||
[[ -n "${ENABLE_MAP[$eng]+x}" ]] && return # user said keep it
|
||||
DISABLE_MAP["$eng"]=1
|
||||
}
|
||||
|
||||
# Auto-disable no-safesearch engines for moderate/strict
|
||||
if [[ "$LEVEL" != "none" ]]; then
|
||||
for eng in "${NO_SAFESEARCH_ENGINES[@]}"; do
|
||||
mark_disabled "$eng"
|
||||
done
|
||||
fi
|
||||
|
||||
# Category disables
|
||||
if [[ -n "$DISABLE_CATS" ]]; then
|
||||
IFS=',' read -ra _cats <<< "$DISABLE_CATS"
|
||||
for cat in "${_cats[@]}"; do
|
||||
cat="${cat#"${cat%%[![:space:]]*}"}"; cat="${cat%"${cat##*[![:space:]]}"}"
|
||||
cat="${cat,,}"
|
||||
case "$cat" in
|
||||
videos) for e in "${VIDEOS_ENGINES[@]}"; do mark_disabled "$e"; done ;;
|
||||
images) for e in "${IMAGES_ENGINES[@]}"; do mark_disabled "$e"; done ;;
|
||||
news) for e in "${NEWS_ENGINES[@]}"; do mark_disabled "$e"; done ;;
|
||||
science) for e in "${SCIENCE_ENGINES[@]}"; do mark_disabled "$e"; done ;;
|
||||
social) for e in "${SOCIAL_ENGINES[@]}"; do mark_disabled "$e"; done ;;
|
||||
"") ;;
|
||||
*) warn "Unknown category '$cat' — valid: videos images news science social" ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Extra engine disables
|
||||
if [[ -n "$DISABLE_ENGINES_EXTRA" ]]; then
|
||||
IFS=',' read -ra _engs <<< "$DISABLE_ENGINES_EXTRA"
|
||||
for e in "${_engs[@]}"; do
|
||||
e="${e#"${e%%[![:space:]]*}"}"; e="${e%"${e##*[![:space:]]}"}"
|
||||
[[ -n "$e" ]] && mark_disabled "$e"
|
||||
done
|
||||
fi
|
||||
|
||||
# ── Preserve existing secret key ─────────────────────────────────────────────
|
||||
SECRET_KEY=$(grep -oP '(?<=secret_key: ")[^"]+' "$SETTINGS" 2>/dev/null || true)
|
||||
[[ -z "$SECRET_KEY" ]] && SECRET_KEY=$(openssl rand -hex 32)
|
||||
|
||||
# ── Build engine override block ───────────────────────────────────────────────
|
||||
ENGINE_BLOCK=""
|
||||
for eng in "${!DISABLE_MAP[@]}"; do
|
||||
ENGINE_BLOCK+=" - name: ${eng}\n disabled: true\n"
|
||||
done
|
||||
for eng in "${!ENABLE_MAP[@]}"; do
|
||||
ENGINE_BLOCK+=" - name: ${eng}\n disabled: false\n"
|
||||
done
|
||||
|
||||
# ── Write settings.yml ────────────────────────────────────────────────────────
|
||||
{
|
||||
printf 'use_default_settings: true\n'
|
||||
printf 'general:\n instance_name: "Local Search"\n'
|
||||
printf 'server:\n secret_key: "%s"\n limiter: false\n' "$SECRET_KEY"
|
||||
printf 'search:\n safe_search: %d\n default_lang: "en"\n formats: [html, json]\n' "$SAFE_INT"
|
||||
if [[ -n "$ENGINE_BLOCK" ]]; then
|
||||
printf 'engines:\n'
|
||||
printf '%b' "$ENGINE_BLOCK"
|
||||
fi
|
||||
} > "$SETTINGS"
|
||||
|
||||
ok "Updated settings.yml (safe_search: $SAFE_INT)"
|
||||
if [[ ${#DISABLE_MAP[@]} -gt 0 ]]; then
|
||||
info "Disabled (${#DISABLE_MAP[@]}): $(printf '%s, ' "${!DISABLE_MAP[@]}" | sed 's/, $//')"
|
||||
fi
|
||||
if [[ ${#ENABLE_MAP[@]} -gt 0 ]]; then
|
||||
info "Re-enabled: $(printf '%s, ' "${!ENABLE_MAP[@]}" | sed 's/, $//')"
|
||||
fi
|
||||
|
||||
# ── Update &safesearch= in SEARXNG_QUERY_URL inside docker-compose.yml ────────
|
||||
if [[ -f "$COMPOSE" ]]; then
|
||||
sed -i -E \
|
||||
"s|(SEARXNG_QUERY_URL=http://searxng:[0-9]+/search\?[^&[:space:]]*)(&safesearch=[0-9])?|\1\&safesearch=${SAFE_INT}|g" \
|
||||
"$COMPOSE"
|
||||
ok "Updated SEARXNG_QUERY_URL (&safesearch=${SAFE_INT})"
|
||||
fi
|
||||
|
||||
# ── Restart SearXNG ───────────────────────────────────────────────────────────
|
||||
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^searxng$'; then
|
||||
info "Restarting SearXNG..."
|
||||
docker restart searxng
|
||||
ok "SearXNG restarted"
|
||||
else
|
||||
info "SearXNG not running — changes take effect on next start"
|
||||
fi
|
||||
|
||||
echo
|
||||
grn "Done — safe search: $LEVEL"
|
||||
[[ "$LEVEL" != "none" ]] && \
|
||||
info "Engines skipped (can't enforce '$LEVEL'): ${#DISABLE_MAP[@]} total"
|
||||
+170
-16
@@ -493,6 +493,156 @@ if $INSTALL_AI; then
|
||||
[[ "${DO_PULL,,}" != "n" ]] && PULL_MODELS=true
|
||||
fi
|
||||
|
||||
# ── Q6: SearXNG safe-search & engine selection ────────────────────────────────
|
||||
SEARXNG_SAFE_LEVEL="none"
|
||||
SEARXNG_SAFE_INT=0
|
||||
SEARXNG_DISABLE_ENGINES=""
|
||||
SEARXNG_ENABLE_ENGINES=""
|
||||
|
||||
if $INSTALL_AI && $SVC_SEARXNG; then
|
||||
echo ""
|
||||
echo -e " ${BOLD}[6/6] SearXNG safe-search${NC}"
|
||||
echo " 0) None — all results, no filtering (default)"
|
||||
echo " 1) Moderate — filter explicit content"
|
||||
echo " 2) Strict — block all explicit content"
|
||||
echo ""
|
||||
read -rp " Choice [0]: " _SAFE_PICK
|
||||
case "${_SAFE_PICK:-0}" in
|
||||
1) SEARXNG_SAFE_LEVEL="moderate"; SEARXNG_SAFE_INT=1 ;;
|
||||
2) SEARXNG_SAFE_LEVEL="strict"; SEARXNG_SAFE_INT=2 ;;
|
||||
*) SEARXNG_SAFE_LEVEL="none"; SEARXNG_SAFE_INT=0 ;;
|
||||
esac
|
||||
|
||||
# Default ON/OFF for an engine given the chosen safe-search level
|
||||
_sxst() {
|
||||
[[ "$SEARXNG_SAFE_LEVEL" == "none" ]] && echo ON && return
|
||||
case "$1" in
|
||||
mojeek|yandex|baidu|naver|invidious|piped|peertube|sepiasearch|\
|
||||
dailymotion|vimeo|imgur|deviantart|flickr) echo OFF ;;
|
||||
*) echo ON ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Whiptail checklist — prints selected engine names (one per line).
|
||||
# ESC returns the engines that were pre-checked ON (keeps defaults unchanged).
|
||||
# Args: "Title" name "Desc" ON|OFF [name "Desc" ON|OFF ...]
|
||||
_sxmenu() {
|
||||
local _t="$1"; shift
|
||||
local -a _n=() _s=() _a=(); local _i=1
|
||||
while [[ $# -ge 3 ]]; do
|
||||
_n+=("$1"); _s+=("$3")
|
||||
_a+=("$_i" "$(printf '%-22s %s' "$1" "$2")" "$3")
|
||||
_i=$(( _i + 1 )); shift 3
|
||||
done
|
||||
local _h=$(( ${#_n[@]} + 9 > 24 ? 24 : ${#_n[@]} + 9 ))
|
||||
local _lh=$(( ${#_n[@]} < 14 ? ${#_n[@]} : 14 ))
|
||||
local _o _j
|
||||
if ! _o=$(whiptail --backtitle "SearXNG — $SEARXNG_SAFE_LEVEL" \
|
||||
--title "$_t" --checklist \
|
||||
"SPACE = toggle ENTER = confirm ESC = use defaults" \
|
||||
"$_h" 72 "$_lh" "${_a[@]}" 3>&1 1>&2 2>&3 2>/dev/null); then
|
||||
for _j in "${!_n[@]}"; do
|
||||
[[ "${_s[$_j]}" == "ON" ]] && printf '%s\n' "${_n[$_j]}"
|
||||
done
|
||||
return
|
||||
fi
|
||||
for _id in $_o; do _id="${_id//\"/}"; printf '%s\n' "${_n[$(( _id-1 ))]}"; done
|
||||
}
|
||||
|
||||
# Engines auto-disabled by configure script for moderate/strict.
|
||||
# If user re-enables one in the menu we pass --enable-engines to override.
|
||||
_SX_AUTOFF=(mojeek yandex baidu naver invidious piped peertube sepiasearch)
|
||||
|
||||
if command -v whiptail &>/dev/null && [[ -t 0 ]]; then
|
||||
_SX_W=$(_sxmenu "Web Search Engines" \
|
||||
"google" "Google" ON \
|
||||
"bing" "Microsoft Bing" ON \
|
||||
"duckduckgo" "DuckDuckGo" ON \
|
||||
"brave" "Brave Search" ON \
|
||||
"startpage" "Startpage (Google proxy)" ON \
|
||||
"qwant" "Qwant" ON \
|
||||
"yahoo" "Yahoo" ON \
|
||||
"ecosia" "Ecosia" ON \
|
||||
"mojeek" "Mojeek [no safe-search]" "$(_sxst mojeek)" \
|
||||
"yandex" "Yandex [unreliable filter]" "$(_sxst yandex)" \
|
||||
"baidu" "Baidu [no safe-search]" "$(_sxst baidu)" \
|
||||
"naver" "Naver [no safe-search]" "$(_sxst naver)")
|
||||
|
||||
_SX_I=$(_sxmenu "Image Search Engines" \
|
||||
"google images" "Google Images" ON \
|
||||
"bing images" "Bing Images" ON \
|
||||
"duckduckgo images" "DuckDuckGo Images" ON \
|
||||
"brave images" "Brave Images" ON \
|
||||
"qwant images" "Qwant Images" ON \
|
||||
"openverse" "Openverse (open license)" ON \
|
||||
"unsplash" "Unsplash (stock photos)" ON \
|
||||
"flickr" "Flickr [no safe-search]" "$(_sxst flickr)" \
|
||||
"imgur" "Imgur [no safe-search]" "$(_sxst imgur)" \
|
||||
"deviantart" "DeviantArt [no filter]" "$(_sxst deviantart)")
|
||||
|
||||
_SX_V=$(_sxmenu "Video Search Engines" \
|
||||
"youtube" "YouTube (via Google)" ON \
|
||||
"bing videos" "Bing Videos" ON \
|
||||
"duckduckgo videos" "DuckDuckGo Videos" ON \
|
||||
"google videos" "Google Videos" ON \
|
||||
"invidious" "Invidious [no filter]" "$(_sxst invidious)" \
|
||||
"piped" "Piped [no filter]" "$(_sxst piped)" \
|
||||
"peertube" "PeerTube [no filter]" "$(_sxst peertube)" \
|
||||
"sepiasearch" "SepiaSearch [no filter]" "$(_sxst sepiasearch)" \
|
||||
"dailymotion" "Dailymotion [no filter]" "$(_sxst dailymotion)" \
|
||||
"vimeo" "Vimeo [no filter]" "$(_sxst vimeo)")
|
||||
|
||||
_SX_N=$(_sxmenu "News Search Engines" \
|
||||
"google news" "Google News" ON \
|
||||
"bing news" "Bing News" ON \
|
||||
"duckduckgo news" "DuckDuckGo News" ON \
|
||||
"brave news" "Brave News" ON \
|
||||
"qwant news" "Qwant News" ON)
|
||||
|
||||
_SX_S=$(_sxmenu "Science / Academic" \
|
||||
"arxiv" "arXiv (preprints)" ON \
|
||||
"semantic scholar" "Semantic Scholar" ON \
|
||||
"pubmed" "PubMed (medical)" ON \
|
||||
"crossref" "Crossref (DOI/papers)" ON \
|
||||
"base" "BASE (open access)" ON)
|
||||
|
||||
_SX_ALL=(
|
||||
"google" "bing" "duckduckgo" "brave" "startpage" "qwant" "yahoo" "ecosia"
|
||||
"mojeek" "yandex" "baidu" "naver"
|
||||
"google images" "bing images" "duckduckgo images" "brave images" "qwant images"
|
||||
"openverse" "unsplash" "flickr" "imgur" "deviantart"
|
||||
"youtube" "bing videos" "duckduckgo videos" "google videos"
|
||||
"invidious" "piped" "peertube" "sepiasearch" "dailymotion" "vimeo"
|
||||
"google news" "bing news" "duckduckgo news" "brave news" "qwant news"
|
||||
"arxiv" "semantic scholar" "pubmed" "crossref" "base"
|
||||
)
|
||||
_SX_SEL=$(printf '%s\n' "$_SX_W" "$_SX_I" "$_SX_V" "$_SX_N" "$_SX_S")
|
||||
|
||||
for _e in "${_SX_ALL[@]}"; do
|
||||
if printf '%s\n' "$_SX_SEL" | grep -qxF "$_e"; then
|
||||
# Selected — if auto-disabled by level, pass --enable-engines to override
|
||||
for _ao in "${_SX_AUTOFF[@]}"; do
|
||||
if [[ "$_e" == "$_ao" ]]; then
|
||||
SEARXNG_ENABLE_ENGINES+="${SEARXNG_ENABLE_ENGINES:+,}${_e}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
SEARXNG_DISABLE_ENGINES+="${SEARXNG_DISABLE_ENGINES:+,}${_e}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Fallback: no whiptail / non-interactive terminal
|
||||
echo ""
|
||||
echo " (whiptail not available — text entry)"
|
||||
echo " Web: google bing duckduckgo brave startpage qwant yahoo"
|
||||
echo " Imgs: google_images bing_images duckduckgo_images flickr imgur"
|
||||
echo " Vids: youtube invidious piped peertube dailymotion vimeo"
|
||||
read -rp " Engines to disable (space-separated, Enter for defaults): " _ENGS
|
||||
SEARXNG_DISABLE_ENGINES="${_ENGS// /,}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Summary ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
@@ -521,6 +671,14 @@ if $INSTALL_AI; then
|
||||
fi
|
||||
fi
|
||||
$SVC_KIWIX && echo " ✓ Kiwix ZIMs → $KIWIX_DIR"
|
||||
if $INSTALL_AI && $SVC_SEARXNG; then
|
||||
_sx="safe_search: $SEARXNG_SAFE_LEVEL"
|
||||
if [[ -n "$SEARXNG_DISABLE_ENGINES" ]]; then
|
||||
_ndis=$(tr ',' '\n' <<< "$SEARXNG_DISABLE_ENGINES" | grep -c .)
|
||||
_sx+=" | ${_ndis} engines disabled"
|
||||
fi
|
||||
echo " ✓ SearXNG → $_sx"
|
||||
fi
|
||||
$PULL_MODELS && echo " ✓ Pull models : $EMBED_MODEL + $FAST_MODEL + $CHAT_MODEL + $CODE_MODEL${REASON_MODEL:+ + $REASON_MODEL}"
|
||||
[[ "$ZIM_CHOICE" == "1" ]] && echo " ✓ Download all ZIMs in background (~130GB)"
|
||||
[[ "$ZIM_CHOICE" == "2" ]] && echo " ✓ Select ZIMs to download (prompted after stack starts)"
|
||||
@@ -674,23 +832,16 @@ ok "mcp_requirements.txt"
|
||||
fi # INSTALL_AI
|
||||
|
||||
# =============================================================================
|
||||
if $INSTALL_AI; then
|
||||
if $INSTALL_AI && $SVC_SEARXNG; then
|
||||
section "SearXNG Config"
|
||||
# =============================================================================
|
||||
write_if_new "$BASE/searxng/settings.yml" << SEARXNG
|
||||
use_default_settings: true
|
||||
general:
|
||||
instance_name: "Local Search"
|
||||
server:
|
||||
secret_key: "$(openssl rand -hex 32)"
|
||||
limiter: false
|
||||
search:
|
||||
safe_search: 0
|
||||
default_lang: "en"
|
||||
formats: [html, json]
|
||||
SEARXNG
|
||||
mkdir -p "$BASE/searxng"
|
||||
_SXARGS=("$SEARXNG_SAFE_LEVEL")
|
||||
[[ -n "$SEARXNG_DISABLE_ENGINES" ]] && _SXARGS+=(--disable-engines "$SEARXNG_DISABLE_ENGINES")
|
||||
[[ -n "$SEARXNG_ENABLE_ENGINES" ]] && _SXARGS+=(--enable-engines "$SEARXNG_ENABLE_ENGINES")
|
||||
BASE="$BASE" bash "$SCRIPT_DIR/configure-searxng-safesearch.sh" "${_SXARGS[@]}"
|
||||
|
||||
fi # INSTALL_AI
|
||||
fi # INSTALL_AI && SVC_SEARXNG
|
||||
|
||||
# =============================================================================
|
||||
section ".env File"
|
||||
@@ -780,8 +931,11 @@ ${OLLAMA_VOLUME_LINE}
|
||||
- ENABLE_OPENAI_API=true
|
||||
- ENABLE_RAG_WEB_SEARCH=true
|
||||
- RAG_WEB_SEARCH_ENGINE=searxng
|
||||
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json
|
||||
- WEBUI_AUTH=false
|
||||
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json&safesearch=${SEARXNG_SAFE_INT}
|
||||
- RAG_WEB_SEARCH_RESULT_COUNT=5
|
||||
- RAG_WEB_SEARCH_CONCURRENT_REQUESTS=10
|
||||
- ENABLE_TOOL_SERVERS=true
|
||||
- WEBUI_AUTH=true
|
||||
- WEBUI_URL=${WEBUI_URL:-}
|
||||
depends_on:
|
||||
ollama:
|
||||
|
||||
+152
-14
@@ -14,6 +14,7 @@ FORCE=false; NO_PULL=false
|
||||
for a in "$@"; do [[ "$a" == "--force" ]] && FORCE=true; [[ "$a" == "--no-pull" ]] && NO_PULL=true; done
|
||||
|
||||
BASE="$HOME/docker/ai-stack"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCAL_IP=$(ip route get 1.1.1.1 2>/dev/null | grep -oP 'src \K\S+' || hostname -I | awk '{print $1}')
|
||||
[[ -z "$LOCAL_IP" ]] && read -rp "Enter LAN IP: " LOCAL_IP
|
||||
|
||||
@@ -43,6 +44,147 @@ info "Base : $BASE"
|
||||
info "IP : $LOCAL_IP"
|
||||
info "GPU : ${VRAM_GB}GB VRAM → $TIER"
|
||||
|
||||
# ── SearXNG safe-search & engine selection ────────────────────────────────────
|
||||
SEARXNG_DISABLE_ENGINES=""
|
||||
SEARXNG_ENABLE_ENGINES=""
|
||||
echo ""
|
||||
echo " SearXNG safe-search level:"
|
||||
echo " 0) None — all results, no filtering (default)"
|
||||
echo " 1) Moderate — filter explicit content"
|
||||
echo " 2) Strict — block all explicit content"
|
||||
echo ""
|
||||
read -rp " Choice [0]: " _SAFE_PICK
|
||||
case "${_SAFE_PICK:-0}" in
|
||||
1) SEARXNG_SAFE_LEVEL="moderate"; SEARXNG_SAFE_INT=1 ;;
|
||||
2) SEARXNG_SAFE_LEVEL="strict"; SEARXNG_SAFE_INT=2 ;;
|
||||
*) SEARXNG_SAFE_LEVEL="none"; SEARXNG_SAFE_INT=0 ;;
|
||||
esac
|
||||
|
||||
# Default ON/OFF for an engine given the chosen safe-search level
|
||||
_sxst() {
|
||||
[[ "$SEARXNG_SAFE_LEVEL" == "none" ]] && echo ON && return
|
||||
case "$1" in
|
||||
mojeek|yandex|baidu|naver|invidious|piped|peertube|sepiasearch|\
|
||||
dailymotion|vimeo|imgur|deviantart|flickr) echo OFF ;;
|
||||
*) echo ON ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Whiptail checklist — prints selected engine names (one per line).
|
||||
# ESC returns the engines that were pre-checked ON (keeps defaults unchanged).
|
||||
_sxmenu() {
|
||||
local _t="$1"; shift
|
||||
local -a _n=() _s=() _a=(); local _i=1
|
||||
while [[ $# -ge 3 ]]; do
|
||||
_n+=("$1"); _s+=("$3")
|
||||
_a+=("$_i" "$(printf '%-22s %s' "$1" "$2")" "$3")
|
||||
_i=$(( _i + 1 )); shift 3
|
||||
done
|
||||
local _h=$(( ${#_n[@]} + 9 > 24 ? 24 : ${#_n[@]} + 9 ))
|
||||
local _lh=$(( ${#_n[@]} < 14 ? ${#_n[@]} : 14 ))
|
||||
local _o _j
|
||||
if ! _o=$(whiptail --backtitle "SearXNG — $SEARXNG_SAFE_LEVEL" \
|
||||
--title "$_t" --checklist \
|
||||
"SPACE = toggle ENTER = confirm ESC = use defaults" \
|
||||
"$_h" 72 "$_lh" "${_a[@]}" 3>&1 1>&2 2>&3 2>/dev/null); then
|
||||
for _j in "${!_n[@]}"; do
|
||||
[[ "${_s[$_j]}" == "ON" ]] && printf '%s\n' "${_n[$_j]}"
|
||||
done
|
||||
return
|
||||
fi
|
||||
for _id in $_o; do _id="${_id//\"/}"; printf '%s\n' "${_n[$(( _id-1 ))]}"; done
|
||||
}
|
||||
|
||||
_SX_AUTOFF=(mojeek yandex baidu naver invidious piped peertube sepiasearch)
|
||||
|
||||
if command -v whiptail &>/dev/null && [[ -t 0 ]]; then
|
||||
_SX_W=$(_sxmenu "Web Search Engines" \
|
||||
"google" "Google" ON \
|
||||
"bing" "Microsoft Bing" ON \
|
||||
"duckduckgo" "DuckDuckGo" ON \
|
||||
"brave" "Brave Search" ON \
|
||||
"startpage" "Startpage (Google proxy)" ON \
|
||||
"qwant" "Qwant" ON \
|
||||
"yahoo" "Yahoo" ON \
|
||||
"ecosia" "Ecosia" ON \
|
||||
"mojeek" "Mojeek [no safe-search]" "$(_sxst mojeek)" \
|
||||
"yandex" "Yandex [unreliable filter]" "$(_sxst yandex)" \
|
||||
"baidu" "Baidu [no safe-search]" "$(_sxst baidu)" \
|
||||
"naver" "Naver [no safe-search]" "$(_sxst naver)")
|
||||
|
||||
_SX_I=$(_sxmenu "Image Search Engines" \
|
||||
"google images" "Google Images" ON \
|
||||
"bing images" "Bing Images" ON \
|
||||
"duckduckgo images" "DuckDuckGo Images" ON \
|
||||
"brave images" "Brave Images" ON \
|
||||
"qwant images" "Qwant Images" ON \
|
||||
"openverse" "Openverse (open license)" ON \
|
||||
"unsplash" "Unsplash (stock photos)" ON \
|
||||
"flickr" "Flickr [no safe-search]" "$(_sxst flickr)" \
|
||||
"imgur" "Imgur [no safe-search]" "$(_sxst imgur)" \
|
||||
"deviantart" "DeviantArt [no filter]" "$(_sxst deviantart)")
|
||||
|
||||
_SX_V=$(_sxmenu "Video Search Engines" \
|
||||
"youtube" "YouTube (via Google)" ON \
|
||||
"bing videos" "Bing Videos" ON \
|
||||
"duckduckgo videos" "DuckDuckGo Videos" ON \
|
||||
"google videos" "Google Videos" ON \
|
||||
"invidious" "Invidious [no filter]" "$(_sxst invidious)" \
|
||||
"piped" "Piped [no filter]" "$(_sxst piped)" \
|
||||
"peertube" "PeerTube [no filter]" "$(_sxst peertube)" \
|
||||
"sepiasearch" "SepiaSearch [no filter]" "$(_sxst sepiasearch)" \
|
||||
"dailymotion" "Dailymotion [no filter]" "$(_sxst dailymotion)" \
|
||||
"vimeo" "Vimeo [no filter]" "$(_sxst vimeo)")
|
||||
|
||||
_SX_N=$(_sxmenu "News Search Engines" \
|
||||
"google news" "Google News" ON \
|
||||
"bing news" "Bing News" ON \
|
||||
"duckduckgo news" "DuckDuckGo News" ON \
|
||||
"brave news" "Brave News" ON \
|
||||
"qwant news" "Qwant News" ON)
|
||||
|
||||
_SX_S=$(_sxmenu "Science / Academic" \
|
||||
"arxiv" "arXiv (preprints)" ON \
|
||||
"semantic scholar" "Semantic Scholar" ON \
|
||||
"pubmed" "PubMed (medical)" ON \
|
||||
"crossref" "Crossref (DOI/papers)" ON \
|
||||
"base" "BASE (open access)" ON)
|
||||
|
||||
_SX_ALL=(
|
||||
"google" "bing" "duckduckgo" "brave" "startpage" "qwant" "yahoo" "ecosia"
|
||||
"mojeek" "yandex" "baidu" "naver"
|
||||
"google images" "bing images" "duckduckgo images" "brave images" "qwant images"
|
||||
"openverse" "unsplash" "flickr" "imgur" "deviantart"
|
||||
"youtube" "bing videos" "duckduckgo videos" "google videos"
|
||||
"invidious" "piped" "peertube" "sepiasearch" "dailymotion" "vimeo"
|
||||
"google news" "bing news" "duckduckgo news" "brave news" "qwant news"
|
||||
"arxiv" "semantic scholar" "pubmed" "crossref" "base"
|
||||
)
|
||||
_SX_SEL=$(printf '%s\n' "$_SX_W" "$_SX_I" "$_SX_V" "$_SX_N" "$_SX_S")
|
||||
|
||||
for _e in "${_SX_ALL[@]}"; do
|
||||
if printf '%s\n' "$_SX_SEL" | grep -qxF "$_e"; then
|
||||
for _ao in "${_SX_AUTOFF[@]}"; do
|
||||
if [[ "$_e" == "$_ao" ]]; then
|
||||
SEARXNG_ENABLE_ENGINES+="${SEARXNG_ENABLE_ENGINES:+,}${_e}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
SEARXNG_DISABLE_ENGINES+="${SEARXNG_DISABLE_ENGINES:+,}${_e}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo ""
|
||||
echo " (whiptail not available — text entry)"
|
||||
echo " Web: google bing duckduckgo brave startpage qwant yahoo"
|
||||
echo " Imgs: google_images bing_images duckduckgo_images flickr imgur"
|
||||
echo " Vids: youtube invidious piped peertube dailymotion vimeo"
|
||||
read -rp " Engines to disable (space-separated, Enter for defaults): " _ENGS
|
||||
SEARXNG_DISABLE_ENGINES="${_ENGS// /,}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
write_if_new() {
|
||||
local dest="$1"; local body; body=$(cat)
|
||||
if [[ ! -f "$dest" ]] || $FORCE; then
|
||||
@@ -481,18 +623,11 @@ ok "requirements.txt + mcp_requirements.txt"
|
||||
# =============================================================================
|
||||
section "SearXNG Config"
|
||||
# =============================================================================
|
||||
write_if_new "$BASE/searxng/settings.yml" << SEARXNG
|
||||
use_default_settings: true
|
||||
general:
|
||||
instance_name: "Local Search"
|
||||
server:
|
||||
secret_key: "$(openssl rand -hex 32)"
|
||||
limiter: false
|
||||
search:
|
||||
safe_search: 0
|
||||
default_lang: "en"
|
||||
formats: [html, json]
|
||||
SEARXNG
|
||||
mkdir -p "$BASE/searxng"
|
||||
_SXARGS=("$SEARXNG_SAFE_LEVEL")
|
||||
[[ -n "$SEARXNG_DISABLE_ENGINES" ]] && _SXARGS+=(--disable-engines "$SEARXNG_DISABLE_ENGINES")
|
||||
[[ -n "$SEARXNG_ENABLE_ENGINES" ]] && _SXARGS+=(--enable-engines "$SEARXNG_ENABLE_ENGINES")
|
||||
BASE="$BASE" bash "$SCRIPT_DIR/configure-searxng-safesearch.sh" "${_SXARGS[@]}"
|
||||
|
||||
# =============================================================================
|
||||
section ".env (tokens — never overwritten)"
|
||||
@@ -553,8 +688,11 @@ services:
|
||||
- ENABLE_OPENAI_API=true
|
||||
- ENABLE_RAG_WEB_SEARCH=true
|
||||
- RAG_WEB_SEARCH_ENGINE=searxng
|
||||
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json
|
||||
- WEBUI_AUTH=false
|
||||
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json&safesearch=${SEARXNG_SAFE_INT}
|
||||
- RAG_WEB_SEARCH_RESULT_COUNT=5
|
||||
- RAG_WEB_SEARCH_CONCURRENT_REQUESTS=10
|
||||
- ENABLE_TOOL_SERVERS=true
|
||||
- WEBUI_AUTH=true
|
||||
depends_on:
|
||||
ollama: {condition: service_healthy}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user