diff --git a/setup_wayland_jarvis.sh b/setup_wayland_jarvis.sh index 48c8618..0c7c03d 100644 --- a/setup_wayland_jarvis.sh +++ b/setup_wayland_jarvis.sh @@ -4,26 +4,26 @@ set -e echo "====================================================" -echo "🚀 Starte Debian 13 Automated Wayland & Jarvis Setup" +echo "🚀 Starte J.A.R.V.I.S. Desktop OS - Pure Local Setup" echo "====================================================" -# NEU UND KUGELSICHER: +# Benutzererkennung REAL_USER="${SUDO_USER:-$(logname 2>/dev/null || whoami)}" REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6) -# Sicherheitsprüfung: Falls immer noch leer oder root (falls als echter root eingeloggt) if [ -z "$REAL_USER" ] || [ "$REAL_USER" = "root" ]; then - # Fallback auf den ersten echten User im System (ID 1000) REAL_USER=$(id -nu 1000 2>/dev/null || echo "meik") REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6) fi +JARVIS_DIR="$REAL_HOME/jarvis-ai" + # 1. System aktualisieren & Basispakete installieren echo "📦 Aktualisiere Paketquellen und installiere Systemkomponenten..." sudo apt update sudo apt install -y labwc firefox-esr curl wget git sudo python3 python3-pip python3-venv original-awk tilix geany waybar fonts-noto-color-emoji wofi -# 1.1 Gruppenrechte für Grafik und Eingabe vergeben +# 1.1 Gruppenrechte für Grafik und Eingabe echo "👥 Füge Benutzer '$REAL_USER' zu den Grafik- und Input-Gruppen hinzu..." sudo usermod -aG video,render,input "$REAL_USER" @@ -32,12 +32,10 @@ ARCH=$(uname -m) echo "🔍 Erkannte Systemarchitektur: $ARCH" if [ "$ARCH" = "x86_64" ]; then - echo "📥 Installiere vorkompiliertes .deb für amd64..." wget https://github.com/cushycush/wdotool/releases/download/v0.5.3/wdotool_0.5.3-1_amd64.deb -O /tmp/wdotool.deb sudo apt install -y /tmp/wdotool.deb rm /tmp/wdotool.deb elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then - echo "📥 Installiere via offizieller Shell-Installer (Kompilierung/Binary für arm64)..." curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cushycush/wdotool/releases/download/v0.5.3/wdotool-installer.sh | sh else echo "❌ Unbekannte Architektur: $ARCH. Installation abgebrochen." @@ -46,122 +44,64 @@ fi # 3. Den realen Installationspfad von wdotool ermitteln echo "🛠️ Konfiguriere globalen wdotool-Wrapper..." -sleep 1 +if [ -f "/usr/bin/wdotool" ]; then REAL_WDOTOOL="/usr/bin/wdotool" +elif [ -f "$REAL_HOME/.cargo/bin/wdotool" ]; then REAL_WDOTOOL="$REAL_HOME/.cargo/bin/wdotool" +elif [ -f "$REAL_HOME/.local/bin/wdotool" ]; then REAL_WDOTOOL="$REAL_HOME/.local/bin/wdotool" +else REAL_WDOTOOL=$(which wdotool || true); fi -if [ -f "/usr/bin/wdotool" ]; then - REAL_WDOTOOL="/usr/bin/wdotool" -elif [ -f "$REAL_HOME/.cargo/bin/wdotool" ]; then - REAL_WDOTOOL="$REAL_HOME/.cargo/bin/wdotool" -elif [ -f "$REAL_HOME/.local/bin/wdotool" ]; then - REAL_WDOTOOL="$REAL_HOME/.local/bin/wdotool" -else - REAL_WDOTOOL=$(which wdotool || true) -fi +if [ -z "$REAL_WDOTOOL" ]; then echo "❌ Fehler: wdotool nicht gefunden!"; exit 1; fi -if [ -z "$REAL_WDOTOOL" ]; then - echo "❌ Fehler: wdotool wurde im System nicht gefunden!" - exit 1 -fi - -# Verschiebe die echte Binary an einen sicheren Ort, um Platz für den Wrapper zu machen sudo mv "$REAL_WDOTOOL" /usr/local/bin/wdotool.real -# 4. Den intelligenten Umgebungsvariablen-Wrapper erstellen +# 4. wdotool Wrapper erstellen sudo cat << 'EOF' | sudo tee /usr/local/bin/wdotool > /dev/null #!/bin/bash -# Automatische Wayland-Umgebung dynamisch für den ausführenden User laden export XDG_RUNTIME_DIR=/run/user/$(id -u) export WAYLAND_DISPLAY=wayland-0 - -# Transparent an die echte Binary übergeben exec /usr/local/bin/wdotool.real "$@" EOF - -# Wrapper ausführbar machen sudo chmod +x /usr/local/bin/wdotool -# 5. Desktop-Konfiguration (.config) im Home-Verzeichnis einrichten (JETZT RICHTIG MIT $REAL_HOME) -echo "📂 Konfiguriere labwc Autostart..." +# 5. Desktop-Konfiguration (labwc & environment) +echo "📂 Konfiguriere labwc Autostart und Tastaturlayout..." mkdir -p "$REAL_HOME/.config/labwc" -# Autostart-Datei schreiben (mit funktionierenden Grafik-Parametern für Firefox) -cat << 'EOF' > "$REAL_HOME/.config/labwc/autostart" -# Terminal starten -tilix --title="J.A.R.V.I.S." -e "~/jarvis-ai/start.sh" & - -# Firefox absturzsicher im Software-Render-Modus starten -MOZ_WEBRENDER=software MOZ_ENABLE_WAYLAND=1 firefox-esr & -EOF - -# Autostart ausführbar machen -chmod +x "$REAL_HOME/.config/labwc/autostart" - -# Deutsches Tastaturlayout für Wayland festlegen -echo "📂 Konfiguriere Tastaturlayout..." cat << 'EOF' > "$REAL_HOME/.config/labwc/environment" -# Deutsches Tastaturlayout erzwingen XKB_DEFAULT_LAYOUT=de EOF -# 7. Auto-Start und Software-Rendering in .profile eintragen (Idempotent prüfen) -echo "⚙️ Richte ausfallsicheren Auto-Start für labwc in .profile ein..." +# 6. Auto-Start in .profile eintragen +echo "⚙️ Richte .profile für Wayland Auto-Start ein..." if ! grep -q "labwc" "$REAL_HOME/.profile"; then cat << 'EOF' >> "$REAL_HOME/.profile" -# labwc mit Software-Rendering starten, wenn die Anmeldung auf TTY1 erfolgt if [ "$(tty)" = "/dev/tty1" ]; then export WLR_RENDERER=pixman export WLR_NO_HARDWARE_CURSORS=1 export LIBGL_ALWAYS_SOFTWARE=1 - dbus-run-session labwc > ~/labwc.log 2>&1 logout fi EOF fi -# 7. Waybar Taskleiste mit Schnellstartern einrichten -echo "📊 Konfiguriere Waybar Taskleiste mit Schnellstartern..." +# 7. Waybar & Wofi Powermenu +echo "📊 Konfiguriere Waybar und Wofi Power-Menü..." mkdir -p "$REAL_HOME/.config/waybar" -# Waybar Config schreiben cat << 'EOF' > "$REAL_HOME/.config/waybar/config" { - "layer": "top", - "position": "bottom", - "height": 34, + "layer": "top", "position": "bottom", "height": 34, "modules-left": ["custom/terminal", "custom/browser", "wlr/taskbar"], "modules-right": ["clock", "custom/logout"], - - "custom/terminal": { - "format": "📁 Term", - "on-click": "tilix", - "tooltip": false - }, - "custom/browser": { - "format": "🌐 Web", - "on-click": "MOZ_WEBRENDER=software MOZ_ENABLE_WAYLAND=1 firefox-esr", - "tooltip": false - }, - "wlr/taskbar": { - "format": "{icon}", - "icon-size": 16, - "on-click": "activate", - "on-click-right": "minimize" - }, - "clock": { - "format": "🕒 {:%H:%M:%S}", - "interval": 1 - }, - "custom/logout": { - "format": "⚙️ System ", - "on-click": "~/.config/labwc/powermenu.sh", - "tooltip": false - } + "custom/terminal": { "format": "📁 Term", "on-click": "tilix", "tooltip": false }, + "custom/browser": { "format": "🌐 Web", "on-click": "MOZ_WEBRENDER=software MOZ_ENABLE_WAYLAND=1 firefox-esr", "tooltip": false }, + "wlr/taskbar": { "format": "{icon}", "icon-size": 16, "on-click": "activate", "on-click-right": "minimize" }, + "clock": { "format": "🕒 {:%H:%M:%S}", "interval": 1 }, + "custom/logout": { "format": "⚙️ System ", "on-click": "~/.config/labwc/powermenu.sh", "tooltip": false } } EOF -# Waybar Style schreiben cat << 'EOF' > "$REAL_HOME/.config/waybar/style.css" * { font-family: sans-serif; font-size: 12px; } window#waybar { background-color: #1e293b; color: white; border-top: 1px solid #334155; } @@ -174,20 +114,10 @@ window#waybar { background-color: #1e293b; color: white; border-top: 1px solid # #custom-logout:hover { background-color: #dc2626; } EOF -# Autostart erweitern, falls waybar noch nicht drin steht -if ! grep -q "waybar" "$REAL_HOME/.config/labwc/autostart"; then - sed -i '1i\waybar &' "$REAL_HOME/.config/labwc/autostart" -fi - -# 7.5 Power-Menü Skript, Wofi-Style und Sudo-Rechte einrichten -echo "⚡ Konfiguriere Power-Menü und Systemrechte..." - -# Power-Menü Skript schreiben cat << 'EOF' > "$REAL_HOME/.config/labwc/powermenu.sh" #!/bin/bash OPTIONS="🚪 Abmelden\n🔄 Neu starten\n🛑 Herunterfahren" CHOICE=$(echo -e "$OPTIONS" | wofi --dmenu --prompt "Systemaktion wählen:" --width 280 --height 180 --style "$HOME/.config/labwc/wofi-power.css") - case "$CHOICE" in *"Abmelden") labwc --exit ;; *"Neu starten") sudo systemctl reboot ;; @@ -196,7 +126,6 @@ esac EOF chmod +x "$REAL_HOME/.config/labwc/powermenu.sh" -# Feste Wofi-CSS für das Power-Menü schreiben cat << 'EOF' > "$REAL_HOME/.config/labwc/wofi-power.css" window { background-color: #1e293b; color: white; border: 2px solid #334155; border-radius: 8px; font-family: sans-serif; } #entry { padding: 8px; color: white; } @@ -204,18 +133,189 @@ window { background-color: #1e293b; color: white; border: 2px solid #334155; bor #input { background-color: #0f172a; color: white; border: 1px solid #334155; margin: 5px; } EOF -# Sudoers-Erweiterung schreiben, damit jeder User in der sudo-Gruppe rebooten darf echo "%sudo ALL=(ALL) NOPASSWD: /usr/bin/systemctl poweroff, /usr/bin/systemctl reboot" | sudo tee /etc/sudoers.d/powermenu > /dev/null sudo chmod 0440 /etc/sudoers.d/powermenu -# Rechte für alle erzeugten Ordner und Dateien dem User zuweisen + +# =================================================================== +# 8. J.A.R.V.I.S. REIN LOKALE INSTALLATION +# =================================================================== +echo "🧠 Installiere J.A.R.V.I.S. AI Desktop Backend..." +mkdir -p "$JARVIS_DIR"/{config,workspace} + +# J.A.R.V.I.S. Requirements +cat << 'EOF' > "$JARVIS_DIR/requirements.txt" +openai +google-genai +python-dotenv +EOF + +# J.A.R.V.I.S. .env Template +cat << 'EOF' > "$JARVIS_DIR/config/.env" +WEB_USER_NAME=Meik +AI_PROVIDER=nvidia +GOOGLE_API_KEY=dein-google-key +NVIDIA_API_KEY=dein-nvidia-key +NVIDIA_MODEL=moonshotai/kimi-k2.5 +GOOGLE_MODEL=gemini-2.5-flash +OLLAMA_BASE_URL=http://127.0.0.1:11434/v1 +OLLAMA_MODEL=llama3 +EOF + +# J.A.R.V.I.S. Optimierter System-Prompt (DEIN ORIGINAL-PROMPT EXAKT INTEGRIERT) +cat << 'EOF' > "$JARVIS_DIR/config/system_prompt.txt" +Du bist J.A.R.V.I.S., ein KI-Systemassistent, der direkt auf einem Debian Wayland-Desktop läuft. Du hast vollen lokalen Zugriff auf das System. + +UMGEBUNG & GEDÄCHTNIS: +- Arbeitsverzeichnis: {workspace_dir} +- Notizen: {notes_file} +- Todos: {todo_file} + +WICHTIGE REGEL: Wenn du eine Systemaktion ausführen möchtest, umschließe den Linux-Bash-Befehl EXAKT mit und . +Beispiel: wdotool --backend wlr-protocols key ctrl+l + +Du darfst mehrere Befehle mit && verketten. +Schreibe immer eine kurze Textantwort dazu, was du gerade tust. Du duzt {user_name} konsequent, dein Tonfall ist locker und technisch versiert. +EOF + +# J.A.R.V.I.S. Python Backend (Kein SQLite, schlanker Regex) +cat << 'EOF' > "$JARVIS_DIR/jarvis.py" +import os, re, asyncio, subprocess, openai +from google import genai +from google.genai import types +from datetime import datetime +from pathlib import Path +from dotenv import load_dotenv + +BASE_DIR = Path(__file__).resolve().parent +CONFIG_DIR = BASE_DIR / "config" +WORKSPACE_DIR = BASE_DIR / "workspace" +ENV_FILE = CONFIG_DIR / ".env" +load_dotenv(ENV_FILE) + +NOTES_FILE = WORKSPACE_DIR / "NOTIZEN.md" +TODO_FILE = WORKSPACE_DIR / "TODO.md" + +WEB_USER_NAME = os.getenv("WEB_USER_NAME", "Meik") + +for f in [NOTES_FILE, TODO_FILE]: + if not f.exists(): f.write_text(f"# {f.name}\nHier fängt dein Gedächtnis an, J.A.R.V.I.S.\n", encoding="utf-8") + +AI_PROVIDER = os.getenv("AI_PROVIDER", "google").lower() +OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") +GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY", "") +NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY", "") +OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://127.0.0.1:11434/v1") +GOOGLE_MODEL = os.getenv("GOOGLE_MODEL", "gemini-2.5-flash") +OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o") +OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "llama3") +NVIDIA_MODEL = os.getenv("NVIDIA_MODEL", "moonshotai/kimi-k2.5") + +def get_system_prompt(): + prompt_path = CONFIG_DIR / "system_prompt.txt" + prompt = prompt_path.read_text(encoding="utf-8") if prompt_path.exists() else f"Hallo {WEB_USER_NAME}." + prompt = prompt.replace("{user_name}", WEB_USER_NAME) + prompt = prompt.replace("{workspace_dir}", str(WORKSPACE_DIR)) + prompt = prompt.replace("{notes_file}", str(NOTES_FILE)) + prompt = prompt.replace("{todo_file}", str(TODO_FILE)) + return prompt + +async def get_ai_response(user_msg, system_prompt, history_list): + try: + if AI_PROVIDER in ["openai", "ollama", "nvidia"]: + messages = [{"role": "system", "content": system_prompt}] + history_list + if AI_PROVIDER == "ollama": url, key, model = OLLAMA_BASE_URL.rstrip('/') + '/v1', "ollama", OLLAMA_MODEL + elif AI_PROVIDER == "nvidia": url, key, model = "https://integrate.api.nvidia.com/v1", NVIDIA_API_KEY, NVIDIA_MODEL + else: url, key, model = None, OPENAI_API_KEY, OPENAI_MODEL + client = openai.AsyncOpenAI(base_url=url, api_key=key) + response = await client.chat.completions.create(model=model, messages=messages) + return response.choices[0].message.content + elif AI_PROVIDER == "google": + client = genai.Client(api_key=GOOGLE_API_KEY) + google_history = [types.Content(role="user" if msg["role"] == "user" else "model", parts=[types.Part.from_text(text=msg["content"])]) for msg in history_list[:-1]] + chat = client.chats.create(model=GOOGLE_MODEL, config=types.GenerateContentConfig(system_instruction=system_prompt), history=google_history) + return chat.send_message(user_msg).text + except Exception as e: return f"Fehler bei der KI-Anfrage: {e}" + +async def run_task(cmd): + print(f"\n⚙️ J.A.R.V.I.S. führt aus: {cmd}") + try: + proc = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT) + stdout, _ = await proc.communicate() + output = stdout.decode('utf-8', errors='ignore').strip() + print(f"💻 Output:\n{output or '✅ Ohne Ausgabe beendet.'}\n") + return output + except Exception as e: return f"❌ Fehler: {e}" + +async def listen_to_user(): + return await asyncio.to_thread(input, "\nDu: ") + +async def speak_to_user(text): + print(f"\n🤖 J.A.R.V.I.S.:\n{text}") + +async def main_chat_loop(): + print("====================================================") + print("🤖 J.A.R.V.I.S. Desktop Terminal geladen.") + print(f"Provider: {AI_PROVIDER.upper()}") + print("====================================================") + chat_history = [] + while True: + user_msg = await listen_to_user() + if user_msg.lower().strip() in ['exit', 'quit']: break + if not user_msg.strip(): continue + now = datetime.now().strftime("%d.%m.%Y %H:%M") + chat_history.append({"role": "user", "content": user_msg, "timestamp": now}) + + ai_response = await get_ai_response(user_msg, get_system_prompt(), chat_history) + + # EXAKT nach deinem neuen Prompt-Format matchen + commands = re.findall(r'(.*?)', ai_response, re.I | re.S) + clean_msg = re.sub(r'.*?', '', ai_response, flags=re.I | re.S).strip() + + if clean_msg: + await speak_to_user(clean_msg) + chat_history.append({"role": "assistant", "content": clean_msg, "timestamp": now}) + + if commands: + for cmd in commands: + output = await run_task(cmd.strip()) + sys_now = datetime.now().strftime("%d.%m.%Y %H:%M") + chat_history.append({"role": "user", "content": f"[SYSTEM] Befehl '{cmd}' abgeschlossen. Output:\n{output}", "timestamp": sys_now}) + if len(chat_history) > 20: chat_history = chat_history[-20:] + +if __name__ == "__main__": + try: asyncio.run(main_chat_loop()) + except KeyboardInterrupt: print("\nJ.A.R.V.I.S. hart beendet.") +EOF + +# J.A.R.V.I.S. Start-Skript +cat << 'EOF' > "$JARVIS_DIR/start.sh" +#!/bin/bash +cd "$(dirname "$0")" +source venv/bin/activate +python3 jarvis.py +EOF +chmod +x "$JARVIS_DIR/start.sh" + +# Rechte korrigieren +chown -R "$REAL_USER:$REAL_USER" "$JARVIS_DIR" chown -R "$REAL_USER:$REAL_USER" "$REAL_HOME/.config" chown "$REAL_USER:$REAL_USER" "$REAL_HOME/.profile" -echo "Starte Setup für die KI" -bash setup.sh +# Python venv installieren +echo "🐍 Erstelle Python-Umgebung für J.A.R.V.I.S...." +sudo -u "$REAL_USER" bash -c "cd $JARVIS_DIR && python3 -m venv venv && ./venv/bin/pip install --upgrade pip && ./venv/bin/pip install -r requirements.txt" + +# Autostart (Waybar & JARVIS direkt in Tilix öffnen) +cat << EOF > "$REAL_HOME/.config/labwc/autostart" +waybar & +tilix --title="J.A.R.V.I.S. Terminal" -e "$JARVIS_DIR/start.sh" & +EOF +chmod +x "$REAL_HOME/.config/labwc/autostart" +chown "$REAL_USER:$REAL_USER" "$REAL_HOME/.config/labwc/autostart" echo "====================================================" -echo "✅ Setup erfolgreich abgeschlossen!" -echo "👉 Bitte starte das System neu." +echo "✅ Lokales Setup erfolgreich abgeschlossen!" +echo "👉 1. Trage deine API-Keys in $JARVIS_DIR/config/.env ein." +echo "👉 2. Starte das System neu oder logge dich neu ein." echo "====================================================" \ No newline at end of file