diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..395fd2d --- /dev/null +++ b/.env.example @@ -0,0 +1,46 @@ +# HomeAI — Shared Configuration Template +# Copy to .env and fill in your values. +# .env is gitignored — never commit it. + +# ─── Data & Paths ────────────────────────────────────────────────────────────── +DATA_DIR=${HOME}/homeai-data +REPO_DIR=${HOME}/Projects/HomeAI + +# ─── Network ─────────────────────────────────────────────────────────────────── +# Set to your machine's local IP (not 127.0.0.1) +HOST_IP=192.168.1.100 + +# ─── P1: Infrastructure ──────────────────────────────────────────────────────── +# Pre-existing instances — set these to your actual URLs +HA_URL=http://localhost:8123 +HA_TOKEN= # Generated in Home Assistant UI → Profile → Security +PORTAINER_URL=https://localhost:9443 +GITEA_URL=http://localhost:3000 + +# Managed by homeai-infra docker-compose +UPTIME_KUMA_URL=http://localhost:3001 +CODE_SERVER_URL=http://localhost:8090 +CODE_SERVER_PASS= # Set in homeai-infra/docker/.env +N8N_URL=http://localhost:5678 +N8N_USER=admin +N8N_PASS= # Set in homeai-infra/docker/.env + +# ─── P2: LLM ─────────────────────────────────────────────────────────────────── +OLLAMA_URL=http://localhost:11434 +OLLAMA_API_URL=http://localhost:11434/v1 +OPEN_WEBUI_URL=http://localhost:3030 +OLLAMA_PRIMARY_MODEL=llama3.3:70b +OLLAMA_FAST_MODEL=qwen2.5:7b + +# ─── P3: Voice ───────────────────────────────────────────────────────────────── +WYOMING_STT_URL=tcp://localhost:10300 +WYOMING_TTS_URL=tcp://localhost:10301 + +# ─── P4: Agent ───────────────────────────────────────────────────────────────── +OPENCLAW_URL=http://localhost:8080 + +# ─── P7: Visual ──────────────────────────────────────────────────────────────── +VTUBE_WS_URL=ws://localhost:8001 + +# ─── P8: Images ──────────────────────────────────────────────────────────────── +COMFYUI_URL=http://localhost:8188 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..919de4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Secrets — never commit +.env +.env.secrets +.env.services +**/secrets.yaml +**/secrets.yml + +# Docker volumes / data +homeai-data/ +**/data/ + +# Python +__pycache__/ +*.pyc +*.pyo +.venv/ +venv/ +*.egg-info/ + +# Node +node_modules/ +dist/ +.cache/ + +# macOS +.DS_Store +*.localized + +# Editor +.vscode/ +*.swp +*.swo + +# Ollama model cache (large binaries) +*.gguf +*.safetensors +*.bin +*.ckpt +*.pt + +# ESPHome secrets +homeai-esp32/esphome/secrets.yaml + +# Generated +homeai-llm/benchmark-results.md +homeai-character/characters/*.json +!homeai-character/characters/.gitkeep diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..409b9f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +# HomeAI Makefile — convenience wrapper around setup.sh +# Run `make help` to see all targets. + +SHELL := /bin/bash +REPO_DIR := $(shell pwd) + +.PHONY: help all status infra llm voice agent character esp32 visual images \ + up down restart logs ps clean + +help: + @echo "" + @echo " HomeAI — Make targets" + @echo "" + @echo " Setup:" + @echo " make all Run full setup (all phases)" + @echo " make infra P1: Docker infra stack" + @echo " make llm P2: Ollama + Open WebUI" + @echo " make voice P3: STT / TTS / Wyoming" + @echo " make agent P4: OpenClaw + skills" + @echo " make character P5: Character Manager" + @echo " make esp32 P6: ESPHome firmware" + @echo " make visual P7: VTube Studio bridge" + @echo " make images P8: ComfyUI" + @echo "" + @echo " Operations:" + @echo " make status Show service health" + @echo " make up Start all Docker services" + @echo " make down Stop all Docker services" + @echo " make restart Restart all Docker services" + @echo " make logs Tail logs (all services)" + @echo " make ps Show running containers" + @echo " make clean Remove stopped containers" + @echo "" + +all: + bash setup.sh all + +status: + bash setup.sh status + +infra: + bash setup.sh p1 + +llm: + bash setup.sh p2 + +voice: + bash setup.sh p3 + +agent: + bash setup.sh p4 + +character: + bash setup.sh p5 + +esp32: + bash setup.sh p6 + +visual: + bash setup.sh p7 + +images: + bash setup.sh p8 + +# ─── Docker operations ───────────────────────────────────────────────────────── +up: + @cd homeai-infra && docker compose -f docker/docker-compose.yml up -d + @cd homeai-llm && docker compose -f docker/docker-compose.yml up -d + +down: + @cd homeai-infra && docker compose -f docker/docker-compose.yml down || true + @cd homeai-llm && docker compose -f docker/docker-compose.yml down || true + +restart: + @cd homeai-infra && docker compose -f docker/docker-compose.yml restart + @cd homeai-llm && docker compose -f docker/docker-compose.yml restart + +logs: + @cd homeai-infra && docker compose -f docker/docker-compose.yml logs -f --tail=50 + +ps: + @docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep homeai || \ + docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + +clean: + @docker container prune -f diff --git a/homeai-agent/setup.sh b/homeai-agent/setup.sh new file mode 100644 index 0000000..be8ac23 --- /dev/null +++ b/homeai-agent/setup.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# homeai-agent/setup.sh — P4: OpenClaw agent + skills + mem0 +# +# Components: +# - OpenClaw — AI agent runtime (port 8080) +# - skills/ — home_assistant, memory, weather, timer, music stubs +# - mem0 — long-term memory (Chroma backend) +# - n8n workflows — morning briefing, notification router, memory backup +# +# Prerequisites: +# - P1 (homeai-infra) — Home Assistant running, HA_TOKEN set +# - P2 (homeai-llm) — Ollama running with llama3.3:70b + nomic-embed-text +# - P3 (homeai-voice) — Wyoming TTS running (for voice output) +# - P5 (homeai-character) — aria.json character config exists + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +source "${REPO_DIR}/scripts/common.sh" + +log_section "P4: Agent (OpenClaw + skills + mem0)" +detect_platform + +# ─── Prerequisite check ──────────────────────────────────────────────────────── +log_info "Checking prerequisites..." + +for service in "http://localhost:11434:Ollama(P2)" "http://localhost:8123:HomeAssistant(P1)"; do + url="${service%%:*}"; name="${service##*:}" + if ! curl -sf "$url" -o /dev/null 2>/dev/null; then + log_warn "$name not reachable at $url" + fi +done + +load_env_services +if [[ -z "${HA_TOKEN:-}" ]]; then + log_warn "HA_TOKEN not set in ~/.env.services — needed for home_assistant skill" +fi + +# ─── TODO: Implementation ────────────────────────────────────────────────────── +cat <<'EOF' + + ┌─────────────────────────────────────────────────────────────────┐ + │ P4: homeai-agent — NOT YET IMPLEMENTED │ + │ │ + │ OPEN QUESTION: Which OpenClaw version/fork to use? │ + │ Decide before implementing. See homeai-agent/PLAN.md. │ + │ │ + │ Implementation steps: │ + │ 1. Install OpenClaw (pip install or git clone) │ + │ 2. Create ~/.openclaw/config.yaml from config/config.yaml.example │ + │ 3. Create skills: home_assistant, memory, weather, timer, music│ + │ 4. Install mem0 + Chroma backend │ + │ 5. Create systemd/launchd service for OpenClaw (port 8080) │ + │ 6. Import n8n workflows from workflows/ │ + │ 7. Smoke test: POST /chat "turn on living room lights" │ + │ │ + │ Interface contracts: │ + │ OPENCLAW_URL=http://localhost:8080 │ + └─────────────────────────────────────────────────────────────────┘ + +EOF + +log_info "P4 is not yet implemented. See homeai-agent/PLAN.md for details." +exit 0 diff --git a/homeai-character/character-manager.jsx b/homeai-character/character-manager.jsx new file mode 100644 index 0000000..33e063d --- /dev/null +++ b/homeai-character/character-manager.jsx @@ -0,0 +1,686 @@ +import { useState, useEffect, useCallback } from "react"; + +const STORAGE_KEY = "ai-character-profiles"; + +const DEFAULT_MODELS = [ + "llama3.3:70b", "qwen2.5:72b", "mistral-large", "llama3.1:8b", + "qwen2.5:14b", "gemma3:27b", "deepseek-r1:14b", "phi4:14b" +]; + +const TTS_MODELS = ["Kokoro", "Chatterbox", "F5-TTS", "Qwen3-TTS", "Piper"]; +const STT_MODELS = ["Whisper Large-v3", "Whisper Medium", "Whisper Small", "Whisper Turbo"]; +const IMAGE_MODELS = ["SDXL", "Flux.1-dev", "Flux.1-schnell", "SD 1.5", "Pony Diffusion"]; + +const PERSONALITY_TRAITS = [ + "Warm", "Witty", "Calm", "Energetic", "Sarcastic", "Nurturing", + "Curious", "Playful", "Formal", "Casual", "Empathetic", "Direct", + "Creative", "Analytical", "Protective", "Mischievous" +]; + +const SPEAKING_STYLES = [ + "Conversational", "Poetic", "Concise", "Verbose", "Academic", + "Informal", "Dramatic", "Deadpan", "Enthusiastic", "Measured" +]; + +const EMPTY_CHARACTER = { + id: null, + name: "", + tagline: "", + avatar: "", + accentColor: "#7c6fff", + personality: { + traits: [], + speakingStyle: "", + coreValues: "", + quirks: "", + backstory: "", + motivation: "", + }, + prompts: { + systemPrompt: "", + wakeWordResponse: "", + fallbackResponse: "", + errorResponse: "", + customPrompts: [], + }, + models: { + llm: "", + tts: "", + stt: "", + imageGen: "", + voiceCloneRef: "", + ttsSpeed: 1.0, + temperature: 0.7, + }, + liveRepresentation: { + live2dModel: "", + idleExpression: "", + speakingExpression: "", + thinkingExpression: "", + happyExpression: "", + vtsTriggers: "", + }, + userNotes: "", + createdAt: null, + updatedAt: null, +}; + +const TABS = ["Identity", "Personality", "Prompts", "Models", "Live2D", "Notes"]; + +const TAB_ICONS = { + Identity: "◈", + Personality: "◉", + Prompts: "◎", + Models: "⬡", + Live2D: "◇", + Notes: "▣", +}; + +function generateId() { + return Date.now().toString(36) + Math.random().toString(36).slice(2); +} + +function ColorPicker({ value, onChange }) { + const presets = [ + "#7c6fff","#ff6b9d","#00d4aa","#ff9f43","#48dbfb", + "#ff6348","#a29bfe","#fd79a8","#55efc4","#fdcb6e" + ]; + return ( +
{hint}
} + {children} +