setup_wayland_jarvis.sh aktualisiert
This commit is contained in:
@@ -4,26 +4,26 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "===================================================="
|
echo "===================================================="
|
||||||
echo "🚀 Starte Debian 13 Automated Wayland & Jarvis Setup"
|
echo "🚀 Starte J.A.R.V.I.S. Desktop OS - Pure Local Setup"
|
||||||
echo "===================================================="
|
echo "===================================================="
|
||||||
|
|
||||||
# NEU UND KUGELSICHER:
|
# Benutzererkennung
|
||||||
REAL_USER="${SUDO_USER:-$(logname 2>/dev/null || whoami)}"
|
REAL_USER="${SUDO_USER:-$(logname 2>/dev/null || whoami)}"
|
||||||
REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
|
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
|
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_USER=$(id -nu 1000 2>/dev/null || echo "meik")
|
||||||
REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
|
REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
JARVIS_DIR="$REAL_HOME/jarvis-ai"
|
||||||
|
|
||||||
# 1. System aktualisieren & Basispakete installieren
|
# 1. System aktualisieren & Basispakete installieren
|
||||||
echo "📦 Aktualisiere Paketquellen und installiere Systemkomponenten..."
|
echo "📦 Aktualisiere Paketquellen und installiere Systemkomponenten..."
|
||||||
sudo apt update
|
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
|
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..."
|
echo "👥 Füge Benutzer '$REAL_USER' zu den Grafik- und Input-Gruppen hinzu..."
|
||||||
sudo usermod -aG video,render,input "$REAL_USER"
|
sudo usermod -aG video,render,input "$REAL_USER"
|
||||||
|
|
||||||
@@ -32,12 +32,10 @@ ARCH=$(uname -m)
|
|||||||
echo "🔍 Erkannte Systemarchitektur: $ARCH"
|
echo "🔍 Erkannte Systemarchitektur: $ARCH"
|
||||||
|
|
||||||
if [ "$ARCH" = "x86_64" ]; then
|
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
|
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
|
sudo apt install -y /tmp/wdotool.deb
|
||||||
rm /tmp/wdotool.deb
|
rm /tmp/wdotool.deb
|
||||||
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
|
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
|
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cushycush/wdotool/releases/download/v0.5.3/wdotool-installer.sh | sh
|
||||||
else
|
else
|
||||||
echo "❌ Unbekannte Architektur: $ARCH. Installation abgebrochen."
|
echo "❌ Unbekannte Architektur: $ARCH. Installation abgebrochen."
|
||||||
@@ -46,122 +44,64 @@ fi
|
|||||||
|
|
||||||
# 3. Den realen Installationspfad von wdotool ermitteln
|
# 3. Den realen Installationspfad von wdotool ermitteln
|
||||||
echo "🛠️ Konfiguriere globalen wdotool-Wrapper..."
|
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
|
if [ -z "$REAL_WDOTOOL" ]; then echo "❌ Fehler: wdotool nicht gefunden!"; exit 1; fi
|
||||||
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 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
|
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
|
sudo cat << 'EOF' | sudo tee /usr/local/bin/wdotool > /dev/null
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Automatische Wayland-Umgebung dynamisch für den ausführenden User laden
|
|
||||||
export XDG_RUNTIME_DIR=/run/user/$(id -u)
|
export XDG_RUNTIME_DIR=/run/user/$(id -u)
|
||||||
export WAYLAND_DISPLAY=wayland-0
|
export WAYLAND_DISPLAY=wayland-0
|
||||||
|
|
||||||
# Transparent an die echte Binary übergeben
|
|
||||||
exec /usr/local/bin/wdotool.real "$@"
|
exec /usr/local/bin/wdotool.real "$@"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Wrapper ausführbar machen
|
|
||||||
sudo chmod +x /usr/local/bin/wdotool
|
sudo chmod +x /usr/local/bin/wdotool
|
||||||
|
|
||||||
# 5. Desktop-Konfiguration (.config) im Home-Verzeichnis einrichten (JETZT RICHTIG MIT $REAL_HOME)
|
# 5. Desktop-Konfiguration (labwc & environment)
|
||||||
echo "📂 Konfiguriere labwc Autostart..."
|
echo "📂 Konfiguriere labwc Autostart und Tastaturlayout..."
|
||||||
mkdir -p "$REAL_HOME/.config/labwc"
|
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"
|
cat << 'EOF' > "$REAL_HOME/.config/labwc/environment"
|
||||||
# Deutsches Tastaturlayout erzwingen
|
|
||||||
XKB_DEFAULT_LAYOUT=de
|
XKB_DEFAULT_LAYOUT=de
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# 7. Auto-Start und Software-Rendering in .profile eintragen (Idempotent prüfen)
|
# 6. Auto-Start in .profile eintragen
|
||||||
echo "⚙️ Richte ausfallsicheren Auto-Start für labwc in .profile ein..."
|
echo "⚙️ Richte .profile für Wayland Auto-Start ein..."
|
||||||
if ! grep -q "labwc" "$REAL_HOME/.profile"; then
|
if ! grep -q "labwc" "$REAL_HOME/.profile"; then
|
||||||
cat << 'EOF' >> "$REAL_HOME/.profile"
|
cat << 'EOF' >> "$REAL_HOME/.profile"
|
||||||
|
|
||||||
# labwc mit Software-Rendering starten, wenn die Anmeldung auf TTY1 erfolgt
|
|
||||||
if [ "$(tty)" = "/dev/tty1" ]; then
|
if [ "$(tty)" = "/dev/tty1" ]; then
|
||||||
export WLR_RENDERER=pixman
|
export WLR_RENDERER=pixman
|
||||||
export WLR_NO_HARDWARE_CURSORS=1
|
export WLR_NO_HARDWARE_CURSORS=1
|
||||||
export LIBGL_ALWAYS_SOFTWARE=1
|
export LIBGL_ALWAYS_SOFTWARE=1
|
||||||
|
|
||||||
dbus-run-session labwc > ~/labwc.log 2>&1
|
dbus-run-session labwc > ~/labwc.log 2>&1
|
||||||
logout
|
logout
|
||||||
fi
|
fi
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 7. Waybar Taskleiste mit Schnellstartern einrichten
|
# 7. Waybar & Wofi Powermenu
|
||||||
echo "📊 Konfiguriere Waybar Taskleiste mit Schnellstartern..."
|
echo "📊 Konfiguriere Waybar und Wofi Power-Menü..."
|
||||||
mkdir -p "$REAL_HOME/.config/waybar"
|
mkdir -p "$REAL_HOME/.config/waybar"
|
||||||
|
|
||||||
# Waybar Config schreiben
|
|
||||||
cat << 'EOF' > "$REAL_HOME/.config/waybar/config"
|
cat << 'EOF' > "$REAL_HOME/.config/waybar/config"
|
||||||
{
|
{
|
||||||
"layer": "top",
|
"layer": "top", "position": "bottom", "height": 34,
|
||||||
"position": "bottom",
|
|
||||||
"height": 34,
|
|
||||||
"modules-left": ["custom/terminal", "custom/browser", "wlr/taskbar"],
|
"modules-left": ["custom/terminal", "custom/browser", "wlr/taskbar"],
|
||||||
"modules-right": ["clock", "custom/logout"],
|
"modules-right": ["clock", "custom/logout"],
|
||||||
|
"custom/terminal": { "format": "📁 Term", "on-click": "tilix", "tooltip": false },
|
||||||
"custom/terminal": {
|
"custom/browser": { "format": "🌐 Web", "on-click": "MOZ_WEBRENDER=software MOZ_ENABLE_WAYLAND=1 firefox-esr", "tooltip": false },
|
||||||
"format": "📁 Term",
|
"wlr/taskbar": { "format": "{icon}", "icon-size": 16, "on-click": "activate", "on-click-right": "minimize" },
|
||||||
"on-click": "tilix",
|
"clock": { "format": "🕒 {:%H:%M:%S}", "interval": 1 },
|
||||||
"tooltip": false
|
"custom/logout": { "format": "⚙️ System ", "on-click": "~/.config/labwc/powermenu.sh", "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
|
EOF
|
||||||
|
|
||||||
# Waybar Style schreiben
|
|
||||||
cat << 'EOF' > "$REAL_HOME/.config/waybar/style.css"
|
cat << 'EOF' > "$REAL_HOME/.config/waybar/style.css"
|
||||||
* { font-family: sans-serif; font-size: 12px; }
|
* { font-family: sans-serif; font-size: 12px; }
|
||||||
window#waybar { background-color: #1e293b; color: white; border-top: 1px solid #334155; }
|
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; }
|
#custom-logout:hover { background-color: #dc2626; }
|
||||||
EOF
|
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"
|
cat << 'EOF' > "$REAL_HOME/.config/labwc/powermenu.sh"
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
OPTIONS="🚪 Abmelden\n🔄 Neu starten\n🛑 Herunterfahren"
|
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")
|
CHOICE=$(echo -e "$OPTIONS" | wofi --dmenu --prompt "Systemaktion wählen:" --width 280 --height 180 --style "$HOME/.config/labwc/wofi-power.css")
|
||||||
|
|
||||||
case "$CHOICE" in
|
case "$CHOICE" in
|
||||||
*"Abmelden") labwc --exit ;;
|
*"Abmelden") labwc --exit ;;
|
||||||
*"Neu starten") sudo systemctl reboot ;;
|
*"Neu starten") sudo systemctl reboot ;;
|
||||||
@@ -196,7 +126,6 @@ esac
|
|||||||
EOF
|
EOF
|
||||||
chmod +x "$REAL_HOME/.config/labwc/powermenu.sh"
|
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"
|
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; }
|
window { background-color: #1e293b; color: white; border: 2px solid #334155; border-radius: 8px; font-family: sans-serif; }
|
||||||
#entry { padding: 8px; color: white; }
|
#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; }
|
#input { background-color: #0f172a; color: white; border: 1px solid #334155; margin: 5px; }
|
||||||
EOF
|
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
|
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
|
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 <EXECUTE> und </EXECUTE>.
|
||||||
|
Beispiel: <EXECUTE>wdotool --backend wlr-protocols key ctrl+l</EXECUTE>
|
||||||
|
|
||||||
|
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'<EXECUTE>(.*?)</EXECUTE>', ai_response, re.I | re.S)
|
||||||
|
clean_msg = re.sub(r'<EXECUTE>.*?</EXECUTE>', '', 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 -R "$REAL_USER:$REAL_USER" "$REAL_HOME/.config"
|
||||||
chown "$REAL_USER:$REAL_USER" "$REAL_HOME/.profile"
|
chown "$REAL_USER:$REAL_USER" "$REAL_HOME/.profile"
|
||||||
|
|
||||||
echo "Starte Setup für die KI"
|
# Python venv installieren
|
||||||
bash setup.sh
|
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 "===================================================="
|
||||||
echo "✅ Setup erfolgreich abgeschlossen!"
|
echo "✅ Lokales Setup erfolgreich abgeschlossen!"
|
||||||
echo "👉 Bitte starte das System neu."
|
echo "👉 1. Trage deine API-Keys in $JARVIS_DIR/config/.env ein."
|
||||||
|
echo "👉 2. Starte das System neu oder logge dich neu ein."
|
||||||
echo "===================================================="
|
echo "===================================================="
|
||||||
Reference in New Issue
Block a user