Posted on
Artificial Intelligence

Artificial Intelligence Projects for Home Labs

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence Projects for Home Labs (Bash-Friendly Builds)

Want privacy, speed, and hands-on skills without renting GPUs in the cloud? Bring AI into your home lab. In a few terminal commands, you can stand up a local LLM API, transcribe audio offline, flag weird log activity, and ask natural-language questions over your personal documents—no data leaving your network.

This guide explains why home-lab AI is worth it, then walks through 4 practical projects with step-by-step Bash and Python snippets. You’ll get installation commands for apt, dnf, and zypper where needed, and small, composable scripts you can extend later.

Why run AI in your home lab?

  • Privacy and data locality: Keep your chats, docs, and logs off third-party clouds.

  • Latency and reliability: Sub-second responses on your LAN, even when the internet is down.

  • Cost control: Use the hardware you already own; scale up only if you need to.

  • Skill building: Learn the Linux and container skills that power modern AI ops.


Project 1: Run a Local LLM API with Ollama (plus llama.cpp option)

What you’ll get: A local HTTP API for chat/completions that you can script with curl. Great for automations, RAG backends, and tinkering.

Install prerequisites (curl)

  • Ubuntu/Debian (apt)
sudo apt update
sudo apt install -y curl
  • Fedora/RHEL (dnf)
sudo dnf install -y curl
  • openSUSE (zypper)
sudo zypper install -y curl

Install Ollama (one-liner)

curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl enable --now ollama

Pull and run a model

ollama pull llama3
ollama run llama3

Tip: Press Ctrl+C to exit the REPL. Keep the daemon running to use the REST API.

Call the REST API from Bash

curl http://localhost:11434/api/generate \
  -d '{"model":"llama3","prompt":"Write a haiku about homelabs."}'

You can also stream responses or use other models like mistral, phi3, qwen2, or small-footprint ones for older CPUs.

Alternative: Build llama.cpp from source (advanced)

Prereqs:

  • Ubuntu/Debian (apt)
sudo apt update
sudo apt install -y git cmake build-essential wget
  • Fedora/RHEL (dnf)
sudo dnf install -y git cmake gcc-c++ make wget
  • openSUSE (zypper)
sudo zypper install -y git cmake gcc-c++ make wget

Build:

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make -j
mkdir -p models

Download a small GGUF model (example: TinyLlama 1.1B Chat). Visit the model page and download a GGUF file into models/. Example:

wget -O models/TinyLlama-1.1B-Chat-v1.0.Q4_K_M.gguf \
  "https://huggingface.co/TinyLlama/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/TinyLlama-1.1B-Chat-v1.0.Q4_K_M.gguf?download=true"

Run:

./main -m models/TinyLlama-1.1B-Chat-v1.0.Q4_K_M.gguf -p "Hello from my homelab!"

Project 2: Offline Speech-to-Text (STT) + Text-to-Speech (TTS) Mini Assistant

What you’ll get: Record your voice, transcribe offline with Vosk, and speak back using espeak-ng—no network calls, simple and fast.

Install prerequisites

  • Ubuntu/Debian (apt)
sudo apt update
sudo apt install -y python3 python3-venv python3-pip sox alsa-utils espeak-ng wget unzip
  • Fedora/RHEL (dnf)
sudo dnf install -y python3 python3-pip sox alsa-utils espeak-ng wget unzip
  • openSUSE (zypper)
sudo zypper install -y python3 python3-pip sox alsa-utils espeak-ng wget unzip

Note: On Debian/Ubuntu, python3-venv ensures “python3 -m venv” works. On Fedora/openSUSE, venv is typically included with python3.

Create a project folder and venv (optional but recommended)

mkdir -p ~/stt && cd ~/stt
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install --upgrade pip
pip install vosk

Download a small English model

wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
unzip -q vosk-model-small-en-us-0.15.zip
mv vosk-model-small-en-us-0.15 model

Record audio (5 seconds) and transcribe

Record:

arecord -f cd -d 5 -q speech.wav

Transcribe (stt.py):

cat > stt.py << 'PY'
import sys, json, wave
from vosk import Model, KaldiRecognizer

wf = wave.open("speech.wav", "rb")
assert wf.getnchannels() == 1 or wf.getframerate() == 16000, \
    "Use mono, 16kHz WAV for best results (tip: sox can convert)"

model = Model("model")
rec = KaldiRecognizer(model, wf.getframerate())
rec.SetWords(True)

text = []
while True:
    data = wf.readframes(4000)
    if len(data) == 0:
        break
    if rec.AcceptWaveform(data):
        text.append(json.loads(rec.Result()).get("text",""))
text.append(json.loads(rec.FinalResult()).get("text",""))
print(" ".join([t for t in text if t]).strip())
PY

Run:

python3 stt.py

Optional TTS reply:

espeak-ng -s 160 "You said: $(python3 stt.py)"

Tips:

  • For better STT quality, use larger models from Vosk’s site.

  • To ensure mono/16kHz input: sox speech.wav -r 16000 -c 1 speech_mono.wav.


Project 3: Detect Suspicious Log Activity with IsolationForest

What you’ll get: A quick anomaly detector for SSH auth logs that flags unusual IPs or spikes. It’s a lightweight way to add some ML to your homelab security checks.

Install prerequisites

  • Ubuntu/Debian (apt)
sudo apt update
sudo apt install -y python3 python3-pip
  • Fedora/RHEL (dnf)
sudo dnf install -y python3 python3-pip
  • openSUSE (zypper)
sudo zypper install -y python3 python3-pip

Set up environment (optional venv) and install packages:

mkdir -p ~/log-ai && cd ~/log-ai
python3 -m venv .venv 2>/dev/null || true
. .venv/bin/activate 2>/dev/null || true
python3 -m pip install --upgrade pip
pip install scikit-learn numpy

Script: parse logs and flag outliers

This script reads /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (Fedora/openSUSE/RHEL), computes simple features per source IP, and uses IsolationForest to score anomalies.

cat > detect_anomalies.py << 'PY'
import os, re, sys, gzip
from datetime import datetime
import numpy as np
from sklearn.ensemble import IsolationForest

paths = ["/var/log/auth.log", "/var/log/auth.log.1", "/var/log/secure", "/var/log/secure-2024*"]
logs = []
for p in paths:
    for candidate in sorted([p] if "*" not in p else [fp for fp in ["/var/log/secure", "/var/log/secure-2024", "/var/log/secure-2023"] if os.path.exists(fp)]):
        if os.path.exists(candidate):
            logs.append(candidate)

if not logs:
    print("No known auth logs found. Try adjusting paths.")
    sys.exit(1)

ip_re = re.compile(r'(\d{1,3}\.){3}\d{1,3}')
fail_re = re.compile(r'Failed password')
ok_re = re.compile(r'Accepted password|Accepted publickey')

stats = {}  # ip -> [fails, oks, hours_active]
hours_seen = {}

def get_hour(ts):
    # Try syslog-like "MMM DD HH:MM:SS"
    try:
        m = re.match(r'^[A-Z][a-z]{2}\s+\d{1,2}\s+(\d{2}):\d{2}:\d{2}', ts)
        if m:
            return int(m.group(1))
    except:
        pass
    return None

def update(ip, line):
    f = 1 if fail_re.search(line) else 0
    o = 1 if ok_re.search(line) else 0
    h = get_hour(line)
    if ip not in stats:
        stats[ip] = [0,0,0]
        hours_seen[ip] = set()
    stats[ip][0] += f
    stats[ip][1] += o
    if h is not None:
        hours_seen[ip].add(h)

for path in logs:
    opener = gzip.open if path.endswith(".gz") else open
    try:
        with opener(path, "rt", errors="ignore") as fh:
            for line in fh:
                m = ip_re.search(line)
                if not m: continue
                ip = m.group(0)
                update(ip, line)
    except Exception as e:
        continue

for ip in stats:
    stats[ip][2] = len(hours_seen[ip])

# Build feature matrix
ips = list(stats.keys())
X = np.array([stats[ip] for ip in ips], dtype=float)
if len(ips) < 5:
    print("Not enough data to model anomalies.")
    sys.exit(0)

model = IsolationForest(n_estimators=200, contamination='auto', random_state=42)
scores = model.fit_predict(X)
anom_idx = np.where(scores == -1)[0]

print("Potentially anomalous IPs (failures, successes, distinct hours):")
for i in anom_idx:
    print(f"{ips[i]:15s}  {stats[ips[i]]}")
PY

Run (you may need sudo for some logs):

sudo python3 detect_anomalies.py

Automate with cron/systemd and alert via mail or a webhook.


Project 4: Private RAG Search Over Your Documents

What you’ll get: Local embeddings with sentence-transformers, a tiny vector store (Chroma), and a CLI to search your notes/wikis. Optional: forward top results to your local LLM (Ollama) for a summarized answer.

Install prerequisites

  • Ubuntu/Debian (apt)
sudo apt update
sudo apt install -y python3 python3-pip
  • Fedora/RHEL (dnf)
sudo dnf install -y python3 python3-pip
  • openSUSE (zypper)
sudo zypper install -y python3 python3-pip

Set up environment and install libs:

mkdir -p ~/rag && cd ~/rag
python3 -m venv .venv 2>/dev/null || true
. .venv/bin/activate 2>/dev/null || true
python3 -m pip install --upgrade pip
pip install "sentence-transformers<3" chromadb

Index a folder of .txt/.md and query

cat > rag.py << 'PY'
import os, glob, sys
import chromadb
from sentence_transformers import SentenceTransformer

docs_dir = sys.argv[1] if len(sys.argv) > 1 else "."
query = sys.argv[2] if len(sys.argv) > 2 else "What is this repository about?"

paths = sorted(glob.glob(os.path.join(docs_dir, "**/*.txt"), recursive=True) +
               glob.glob(os.path.join(docs_dir, "**/*.md"), recursive=True))

if not paths:
    print("No .txt/.md files found.")
    sys.exit(0)

model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
client = chromadb.Client()
col = client.get_or_create_collection("local_docs")

# Clear and (re)index quickly for demo
try:
    client.delete_collection("local_docs")
    col = client.create_collection("local_docs")
except:
    pass

docs = []
metas = []
ids = []
for i, p in enumerate(paths):
    with open(p, "r", errors="ignore") as f:
        txt = f.read()
    docs.append(txt)
    metas.append({"path": p})
    ids.append(str(i))

col.add(documents=docs, metadatas=metas, ids=ids)

res = col.query(query_texts=[query], n_results=3)
print("Top matches:")
for doc, meta in zip(res["documents"][0], res["metadatas"][0]):
    print(f"- {meta['path']}\n  {doc[:300].replace('\\n',' ')}...")
PY

Run:

python3 rag.py ~/Documents "How do I deploy my service?"

Optional: Summarize with Ollama. Pull a chat model and then:

read -r CONTEXT << 'EOF'
$(python3 rag.py ~/Documents "How do I deploy my service?")
EOF

curl http://localhost:11434/api/generate \
  -d "{\"model\":\"llama3\",\"prompt\":\"Using the context below, answer succinctly: How do I deploy my service?\n\n$CONTEXT\"}"

Operational tips

  • Hardware: CPU-only works for small models; GPUs/NPUs accelerate everything. Try smaller “instruct” models first.

  • Services: Use systemd user services or containers (e.g., podman) to keep things running after reboot.

  • Storage: Model files and embeddings can be large—use a fast SSD.

  • Security: Treat local AI endpoints like any service; firewall, auth, and logs matter.


Conclusion and next steps

You now have four practical, privacy-friendly AI capabilities running locally:

  • A chat/completions API (Ollama or llama.cpp)

  • Offline speech transcription and TTS

  • Anomaly detection on auth logs

  • RAG-style semantic search over your docs

Pick one, ship it this weekend, and then wire them together. For example, feed your RAG results into the LLM, or have your voice assistant trigger queries and read back answers. When you’re ready, wrap them with systemd units, expose them behind a reverse proxy on your homelab network, and share them with your family or team.

If you want a follow-up with systemd units, podman-compose files, or GPU acceleration guides, say the word—happy to help you harden and scale your setup.