mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
Compare commits
4 Commits
84cd2ded50
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 90e4ded7c9 | |||
| c1275d47a6 | |||
| 08fbfaa3e4 | |||
| 1f25b5d04d |
@@ -175,7 +175,7 @@ def fetch_ha_states(cfg: dict) -> list:
|
|||||||
dt = datetime.fromisoformat(lc.replace("Z", "+00:00"))
|
dt = datetime.fromisoformat(lc.replace("Z", "+00:00"))
|
||||||
lc = dt.astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
lc = dt.astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
except Exception:
|
except Exception:
|
||||||
lc = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
lc = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
entities.append({
|
entities.append({
|
||||||
"entity_id": entity_id,
|
"entity_id": entity_id,
|
||||||
@@ -194,13 +194,11 @@ def main():
|
|||||||
heartbeat_every = int(cfg.get("heartbeat_every", 10))
|
heartbeat_every = int(cfg.get("heartbeat_every", 10))
|
||||||
|
|
||||||
api_key = state.get("api_key", "")
|
api_key = state.get("api_key", "")
|
||||||
if not api_key:
|
while not api_key:
|
||||||
api_key = register(cfg, state)
|
api_key = register(cfg, state)
|
||||||
if not api_key:
|
if not api_key:
|
||||||
log("Could not register. Retrying in 60s...")
|
log("Could not register. Retrying in 60s...")
|
||||||
time.sleep(60)
|
time.sleep(60)
|
||||||
main()
|
|
||||||
return
|
|
||||||
|
|
||||||
headers = {"X-Agent-Key": api_key}
|
headers = {"X-Agent-Key": api_key}
|
||||||
last_push = 0
|
last_push = 0
|
||||||
@@ -229,6 +227,7 @@ def main():
|
|||||||
last_push = now
|
last_push = now
|
||||||
else:
|
else:
|
||||||
log("No HA entities fetched (HA down or token invalid?)")
|
log("No HA entities fetched (HA down or token invalid?)")
|
||||||
|
last_push = now
|
||||||
|
|
||||||
time.sleep(heartbeat_every)
|
time.sleep(heartbeat_every)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# JARVIS Network Scanner — runs on PVE1, pushes nmap results to JARVIS
|
||||||
|
# Cron: */3 * * * * /usr/local/bin/jarvis-netscan.sh >/dev/null 2>&1
|
||||||
|
|
||||||
|
JARVIS_URL="http://10.48.200.211"
|
||||||
|
JARVIS_HOST="jarvis.orbishosting.com"
|
||||||
|
REG_KEY=$(cat /etc/jarvis-agent/reg-key 2>/dev/null)
|
||||||
|
if [ -z "$REG_KEY" ]; then
|
||||||
|
echo "$(date): ERROR: /etc/jarvis-agent/reg-key not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SUBNET="10.48.200.0/24"
|
||||||
|
|
||||||
|
TMPFILE=$(mktemp)
|
||||||
|
nmap -sn --send-ip "$SUBNET" 2>/dev/null > "$TMPFILE"
|
||||||
|
|
||||||
|
if [ ! -s "$TMPFILE" ]; then
|
||||||
|
echo "$(date): nmap produced no output" >&2
|
||||||
|
rm -f "$TMPFILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
JSON=$(python3 - "$TMPFILE" <<'PYEOF'
|
||||||
|
import sys, re, json
|
||||||
|
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
devices = []
|
||||||
|
cur = None
|
||||||
|
|
||||||
|
for line in data.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
m = re.match(r'Nmap scan report for (?:(\S+) \()?(\d+\.\d+\.\d+\.\d+)\)?', line)
|
||||||
|
if m:
|
||||||
|
if cur:
|
||||||
|
devices.append(cur)
|
||||||
|
hn = m.group(1) if m.group(1) and m.group(1) != m.group(2) else ''
|
||||||
|
cur = {'ip': m.group(2), 'hostname': hn, 'mac': '', 'vendor': ''}
|
||||||
|
elif cur:
|
||||||
|
m2 = re.match(r'MAC Address: ([0-9A-Fa-f:]{17}) \(([^)]+)\)', line)
|
||||||
|
if m2:
|
||||||
|
cur['mac'] = m2.group(1).lower()
|
||||||
|
cur['vendor'] = '' if m2.group(2) == 'Unknown' else m2.group(2)
|
||||||
|
|
||||||
|
if cur:
|
||||||
|
devices.append(cur)
|
||||||
|
|
||||||
|
print(json.dumps({'devices': devices}))
|
||||||
|
PYEOF
|
||||||
|
)
|
||||||
|
|
||||||
|
rm -f "$TMPFILE"
|
||||||
|
|
||||||
|
if [ -z "$JSON" ]; then
|
||||||
|
echo "$(date): JSON parse failed" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RESPONSE=$(curl -sk --max-time 15 \
|
||||||
|
-X POST "$JARVIS_URL/api/netscan" \
|
||||||
|
-H "Host: $JARVIS_HOST" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-Registration-Key: $REG_KEY" \
|
||||||
|
-d "$JSON" 2>/dev/null)
|
||||||
|
|
||||||
|
echo "$(date): $RESPONSE"
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# JARVIS VoIP Phone Probe — runs every minute on PVE1
|
||||||
|
# Pings all Yealink phones + checks FusionPBX SIP registration (read-only)
|
||||||
|
# 200.3 is on an external FusionPBX — ping only, no SIP check
|
||||||
|
|
||||||
|
JARVIS_URL="http://10.48.200.211"
|
||||||
|
JARVIS_HOST="jarvis.orbishosting.com"
|
||||||
|
REG_KEY=$(cat /etc/jarvis-agent/reg-key 2>/dev/null)
|
||||||
|
if [ -z "$REG_KEY" ]; then
|
||||||
|
echo "$(date): ERROR: /etc/jarvis-agent/reg-key not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
FUSION_HOST="134.209.72.226"
|
||||||
|
|
||||||
|
# IP|alias|extension(none=skip SIP check)|mac
|
||||||
|
PHONES=(
|
||||||
|
"10.48.200.2|Yealink — Myron Main (Ext 1000)|1000|80:5e:c0:35:04:77"
|
||||||
|
"10.48.200.3|Yealink — United Mirror & Glass (External SIP)|none|c4:fc:22:28:63:71"
|
||||||
|
"10.48.200.43|Yealink T48S — Tommy Main (Ext 1001)|1001|80:5e:0c:15:0c:4f"
|
||||||
|
"10.48.200.86|Yealink — Myron Vanguard WiFi (Offline During Work Hrs)|none|"
|
||||||
|
"10.48.200.65|Yealink — Myron Vanguard Work (Ext 1003)|1003|c4:fc:22:13:e1:89"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get SIP registrations from FusionPBX (read-only)
|
||||||
|
REG_OUTPUT=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -o BatchMode=yes \
|
||||||
|
root@$FUSION_HOST "fs_cli -x 'show registrations'" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# Collect results as TSV, delegate JSON building to python3 to avoid injection
|
||||||
|
RESULTS=""
|
||||||
|
for PHONE in "${PHONES[@]}"; do
|
||||||
|
IFS='|' read -r IP ALIAS EXT MAC <<< "$PHONE"
|
||||||
|
|
||||||
|
if ping -c 1 -W 2 "$IP" > /dev/null 2>&1; then
|
||||||
|
STATUS="online"
|
||||||
|
else
|
||||||
|
STATUS="offline"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$EXT" = "none" ]; then
|
||||||
|
SIP="external"
|
||||||
|
elif [ -n "$REG_OUTPUT" ] && echo "$REG_OUTPUT" | grep -q "^${EXT},"; then
|
||||||
|
SIP="registered"
|
||||||
|
else
|
||||||
|
SIP="unregistered"
|
||||||
|
fi
|
||||||
|
|
||||||
|
RESULTS="${RESULTS}${IP}\t${ALIAS}\t${MAC}\t${STATUS}\t${SIP}\t${EXT}\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
JSON=$(printf "%b" "$RESULTS" | python3 -c "
|
||||||
|
import sys, json
|
||||||
|
devices = []
|
||||||
|
for line in sys.stdin:
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
parts = line.split('\t')
|
||||||
|
if len(parts) < 6:
|
||||||
|
continue
|
||||||
|
ip, alias, mac, status, sip, ext = parts[:6]
|
||||||
|
devices.append({
|
||||||
|
'ip': ip, 'alias': alias, 'mac': mac,
|
||||||
|
'vendor': 'Yealink', 'status': status,
|
||||||
|
'sip_status': sip, 'extension': ext,
|
||||||
|
})
|
||||||
|
print(json.dumps({'devices': devices}))
|
||||||
|
")
|
||||||
|
|
||||||
|
curl -sk --max-time 10 \
|
||||||
|
-X POST "$JARVIS_URL/api/netscan" \
|
||||||
|
-H "Host: $JARVIS_HOST" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-Registration-Key: $REG_KEY" \
|
||||||
|
-d "$JSON" > /dev/null 2>&1
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
JARVIS Ping Probe — runs on PVE1 (10.48.200.90), which is on the LAN.
|
||||||
|
Pings devices that can't run the full agent, then calls JARVIS heartbeat
|
||||||
|
on their behalf so the dashboard shows live status.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
import ssl
|
||||||
|
|
||||||
|
JARVIS_URL = "http://10.48.200.211"
|
||||||
|
HOST_HEADER = "jarvis.orbishosting.com"
|
||||||
|
|
||||||
|
# Devices to probe: agent_id → api_key
|
||||||
|
DEVICES = {
|
||||||
|
"fortigate_gw": "00103aea6fcbf837bc55e11b445a3620",
|
||||||
|
"yealink_t48s": "2bf8bd7ca8dd31c28fd16aa956e15f88",
|
||||||
|
"homeassistant_ha": "6f8077dee7a7b4af202bc80886f1223d",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map agent_id → IP (for ping)
|
||||||
|
IPS = {
|
||||||
|
"fortigate_gw": "10.48.200.1",
|
||||||
|
"yealink_t48s": "10.48.200.43",
|
||||||
|
"homeassistant_ha": "10.48.200.97",
|
||||||
|
}
|
||||||
|
|
||||||
|
def ping(ip: str) -> bool:
|
||||||
|
result = subprocess.run(
|
||||||
|
["ping", "-c", "1", "-W", "2", ip],
|
||||||
|
capture_output=True, timeout=5
|
||||||
|
)
|
||||||
|
return result.returncode == 0
|
||||||
|
|
||||||
|
def heartbeat(agent_id: str, api_key: str, alive: bool):
|
||||||
|
# If device is down we still send heartbeat so JARVIS updates last_seen
|
||||||
|
# and sets status based on the alive flag via the metric payload
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
payload = json.dumps({}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
f"{JARVIS_URL}/api/agent/heartbeat",
|
||||||
|
data=payload, method="POST"
|
||||||
|
)
|
||||||
|
req.add_header("Content-Type", "application/json")
|
||||||
|
req.add_header("X-Agent-Key", api_key)
|
||||||
|
req.add_header("Host", HOST_HEADER)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=10, context=ctx):
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_status(agent_id: str, api_key: str, status: str):
|
||||||
|
"""Push a minimal metric so JARVIS knows if device is up or down."""
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
payload = json.dumps({
|
||||||
|
"type": "system",
|
||||||
|
"data": {
|
||||||
|
"hostname": agent_id,
|
||||||
|
"cpu_percent": 0,
|
||||||
|
"ping_only": True,
|
||||||
|
"ping_status": status,
|
||||||
|
}
|
||||||
|
}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
f"{JARVIS_URL}/api/agent/metrics",
|
||||||
|
data=payload, method="POST"
|
||||||
|
)
|
||||||
|
req.add_header("Content-Type", "application/json")
|
||||||
|
req.add_header("X-Agent-Key", api_key)
|
||||||
|
req.add_header("Host", HOST_HEADER)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=10, context=ctx):
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def main():
|
||||||
|
for agent_id, api_key in DEVICES.items():
|
||||||
|
ip = IPS.get(agent_id, "")
|
||||||
|
alive = ping(ip) if ip else False
|
||||||
|
status = "online" if alive else "offline"
|
||||||
|
print(f"{agent_id} ({ip}): {status}", flush=True)
|
||||||
|
heartbeat(agent_id, api_key, alive)
|
||||||
|
update_status(agent_id, api_key, status)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -111,7 +111,8 @@ switch ($agentAction) {
|
|||||||
|
|
||||||
// ── HEARTBEAT ────────────────────────────────────────────────────────────
|
// ── HEARTBEAT ────────────────────────────────────────────────────────────
|
||||||
case 'heartbeat':
|
case 'heartbeat':
|
||||||
update_agent_seen($agent['agent_id'], 'online', trim($data['version'] ?? '') ?: null);
|
$hbStatus = in_array($data['status'] ?? '', ['online','offline']) ? $data['status'] : 'online';
|
||||||
|
update_agent_seen($agent['agent_id'], $hbStatus, trim($data['version'] ?? '') ?: null);
|
||||||
|
|
||||||
// Return any pending commands for this agent
|
// Return any pending commands for this agent
|
||||||
$commands = JarvisDB::query(
|
$commands = JarvisDB::query(
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ function collect_all(): array {
|
|||||||
$results['sites'] = 'skipped (fresh)';
|
$results['sites'] = 'skipped (fresh)';
|
||||||
} else try {
|
} else try {
|
||||||
$sites = [
|
$sites = [
|
||||||
"jarvis" => "http://jarvis.orbishosting.com:1972",
|
"jarvis" => "http://127.0.0.1",
|
||||||
'tomsjavajive' => 'https://tomsjavajive.com',
|
'tomsjavajive' => 'https://tomsjavajive.com',
|
||||||
'epictravelexp'=> 'https://epictravelexpeditions.com',
|
'epictravelexp'=> 'https://epictravelexpeditions.com',
|
||||||
'parkersling' => 'https://parkerslingshotrentals.com',
|
'parkersling' => 'https://parkerslingshotrentals.com',
|
||||||
|
|||||||
+11
-11
@@ -55,7 +55,7 @@ CREATE TABLE `agent_metrics` (
|
|||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_agent_time` (`agent_id`,`recorded_at`),
|
KEY `idx_agent_time` (`agent_id`,`recorded_at`),
|
||||||
KEY `idx_recorded` (`recorded_at`)
|
KEY `idx_recorded` (`recorded_at`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=29445 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=31422 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -182,7 +182,7 @@ CREATE TABLE `conversations` (
|
|||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_session` (`session_id`),
|
KEY `idx_session` (`session_id`),
|
||||||
KEY `idx_created` (`created_at`)
|
KEY `idx_created` (`created_at`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=325 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=335 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -206,7 +206,7 @@ CREATE TABLE `ha_entities` (
|
|||||||
UNIQUE KEY `uk_agent_entity` (`agent_id`,`entity_id`),
|
UNIQUE KEY `uk_agent_entity` (`agent_id`,`entity_id`),
|
||||||
KEY `idx_domain` (`domain`),
|
KEY `idx_domain` (`domain`),
|
||||||
KEY `idx_updated` (`updated_at`)
|
KEY `idx_updated` (`updated_at`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=8436 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=77909 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -226,7 +226,7 @@ CREATE TABLE `kb_facts` (
|
|||||||
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `unique_fact` (`category`,`fact_key`,`host`)
|
UNIQUE KEY `unique_fact` (`category`,`fact_key`,`host`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=39129 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=41478 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -247,7 +247,7 @@ CREATE TABLE `kb_intents` (
|
|||||||
`active` tinyint(1) DEFAULT 1,
|
`active` tinyint(1) DEFAULT 1,
|
||||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -266,7 +266,7 @@ CREATE TABLE `kb_ollama_models` (
|
|||||||
`pulled_at` timestamp NULL DEFAULT current_timestamp(),
|
`pulled_at` timestamp NULL DEFAULT current_timestamp(),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `model_name` (`model_name`)
|
UNIQUE KEY `model_name` (`model_name`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -283,7 +283,7 @@ CREATE TABLE `kb_preferences` (
|
|||||||
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `pref_key` (`pref_key`)
|
UNIQUE KEY `pref_key` (`pref_key`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -340,7 +340,7 @@ CREATE TABLE `network_devices` (
|
|||||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `uk_ip` (`ip`)
|
UNIQUE KEY `uk_ip` (`ip`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=409 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=5556 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -406,10 +406,10 @@ CREATE TABLE `usage_patterns` (
|
|||||||
`hour` tinyint(2) NOT NULL,
|
`hour` tinyint(2) NOT NULL,
|
||||||
`dow` tinyint(1) NOT NULL,
|
`dow` tinyint(1) NOT NULL,
|
||||||
`hit_count` int(11) DEFAULT 1,
|
`hit_count` int(11) DEFAULT 1,
|
||||||
`last_used` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
`last_seen` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `uk_intent_time` (`intent_name`,`hour`,`dow`)
|
UNIQUE KEY `uk_intent_time` (`intent_name`,`hour`,`dow`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -441,4 +441,4 @@ CREATE TABLE `users` (
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2026-06-29 20:43:24
|
-- Dump completed on 2026-06-29 23:15:44
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
-- JARVIS KB Seed Data
|
||||||
|
-- Preferences
|
||||||
|
INSERT INTO kb_preferences (pref_key, pref_value) VALUES
|
||||||
|
('user_name', 'Myron'),
|
||||||
|
('user_title', 'Mr. Blair'),
|
||||||
|
('ai_model', 'llama3.1:8b'),
|
||||||
|
('timezone', 'America/Chicago')
|
||||||
|
ON DUPLICATE KEY UPDATE pref_value = VALUES(pref_value);
|
||||||
|
|
||||||
|
-- Intents: greeting, time, system, network, proxmox, ollama, tasks, HA
|
||||||
|
INSERT INTO kb_intents (intent_name, pattern, response_template, fact_category, action_type, priority, active) VALUES
|
||||||
|
|
||||||
|
-- Greetings
|
||||||
|
('greeting', '(?i)^(hello|hi|hey|good (morning|afternoon|evening)|what.?s up|howdy)\\b', 'Good {current_time}, {user_title}. All systems are online. How can I assist you?', 'system', 'response', 10, 1),
|
||||||
|
|
||||||
|
-- Time / date
|
||||||
|
('current_time', '(?i)\\b(what.?s the (time|current time)|what time is it|tell me the time)\\b', 'It is currently {current_time}, {user_title}.', NULL, 'response', 9, 1),
|
||||||
|
('current_date', '(?i)\\b(what.?s (today.?s date|the date)|what day is it|today.?s date)\\b', 'Today is {current_date}, {user_title}.', NULL, 'response', 9, 1),
|
||||||
|
|
||||||
|
-- System status
|
||||||
|
('system_status', '(?i)\\b(system (status|health)|how.?s (the system|everything)|jarvis status|all systems)\\b', 'JARVIS is fully operational, {user_title}. CPU: {cpu_usage}%, Memory: {mem_percent}% used ({mem_used_gb}GB / {mem_total_gb}GB). Disk: {disk_used} used of {disk_total}. Uptime: {uptime}. Network agents: {online_count}/{total_count} online.', 'system', 'response', 8, 1),
|
||||||
|
('cpu_status', '(?i)\\b(cpu|processor) (usage|load|status|percent|utilization)\\b', 'Current CPU usage is {cpu_usage}%, {user_title}. Load averages: {load_1m} (1m), {load_5m} (5m), {load_15m} (15m).', 'system', 'response', 8, 1),
|
||||||
|
('memory_status', '(?i)\\b(memory|ram|mem) (usage|status|free|used|available)\\b', 'Memory: {mem_used_gb}GB used of {mem_total_gb}GB ({mem_percent}% utilized), {user_title}. Free: {mem_free_gb}GB.', 'system', 'response', 8, 1),
|
||||||
|
('disk_status', '(?i)\\b(disk|storage|drive) (usage|space|status|free|used|available)\\b', 'Disk status: {disk_used} used of {disk_total} total, {disk_free} free, {user_title}.', 'system', 'response', 8, 1),
|
||||||
|
('uptime', '(?i)\\b(uptime|how long.*running|how long.*up|server uptime)\\b', 'JARVIS has been running for {uptime}, {user_title}.', 'system', 'response', 7, 1),
|
||||||
|
|
||||||
|
-- Network status
|
||||||
|
('network_status', '(?i)\\b(network (status|health|agents)|agents (online|status)|how many (agents|devices) (online|running))\\b', 'Network status: {online_count} of {total_count} agents are online, {user_title}.', 'network', 'response', 8, 1),
|
||||||
|
('network_scan', '(?i)\\b(run (a )?network scan|scan (the )?network|nmap scan|network devices)\\b', 'Initiating network scan, {user_title}.', NULL, 'action', 7, 1),
|
||||||
|
|
||||||
|
-- Proxmox
|
||||||
|
('proxmox_status', '(?i)\\b(proxmox (status|health)|vm (status|count|summary)|virtual machines|how many vms)\\b', 'Proxmox: {vm_running} of {vm_total} VMs/containers running, {user_title}. Host CPU: {pve_cpu_percent}%, Memory: {pve_mem_used_gb}GB / {pve_mem_total_gb}GB ({pve_mem_percent}%).', 'proxmox', 'response', 8, 1),
|
||||||
|
('vm_suggestions', '(?i)\\b(vm (resources|performance|usage)|check vms|resource usage)\\b', 'Checking VM resource usage, {user_title}.', 'proxmox', 'action', 7, 1),
|
||||||
|
|
||||||
|
-- Ollama / AI
|
||||||
|
('ollama_status', '(?i)\\b(ollama (status|health|models)|ai models|llm status|local (ai|models))\\b', 'Ollama is {status} with {model_count} model(s) available: {available_models}, {user_title}.', 'ollama', 'response', 7, 1),
|
||||||
|
|
||||||
|
-- Site health
|
||||||
|
('site_status', '(?i)\\b(site(s)? (status|health|up|down)|website status|are (the )?sites (up|down))\\b', 'Site health — jarvis: {jarvis}, orbishosting: {orbishosting}, tomtomgames: {tomtomgames}, tomsjavajive: {tomsjavajive}, parkerslingshotrentals: {parkersling}, epictravelexpeditions: {epictravelexp}, {user_title}.', 'sites', 'response', 7, 1),
|
||||||
|
|
||||||
|
-- Tasks / planner
|
||||||
|
('task_count', '(?i)\\b(how many tasks|pending tasks|task (count|summary)|my tasks)\\b', 'You have {pending_count} pending tasks and {overdue_count} overdue, {user_title}.', NULL, 'response', 7, 1),
|
||||||
|
('planner_briefing', '(?i)\\b((daily )?briefing|what.?s (on|happening) today|today.?s schedule|morning briefing)\\b', 'Fetching your daily briefing, {user_title}.', NULL, 'action', 8, 1),
|
||||||
|
|
||||||
|
-- Home Assistant
|
||||||
|
('ha_lights_on', '(?i)\\b(turn (on|off) (the |all )?lights?|lights? (on|off)|switch (on|off) (the )?lights?)\\b', 'Sending light command, {user_title}.', NULL, 'action', 8, 1),
|
||||||
|
('ha_scene', '(?i)\\b(activate (a |the )?scene|set (a |the )?scene|home scene)\\b', 'Activating home scene, {user_title}.', NULL, 'action', 7, 1),
|
||||||
|
|
||||||
|
-- Jellyfin
|
||||||
|
('jellyfin_now_playing', '(?i)\\b(what.?s (playing|on)|now playing|jellyfin.*playing|playing.*jellyfin)\\b', 'Checking Jellyfin now playing, {user_title}.', NULL, 'action', 7, 1),
|
||||||
|
('jellyfin_library', '(?i)\\b(jellyfin (library|media|shows?|movies?)|media library|show.*library)\\b', 'Fetching Jellyfin library, {user_title}.', NULL, 'action', 6, 1),
|
||||||
|
('jellyfin_pause', '(?i)\\b(pause (jellyfin|playback|media)|stop (playing|jellyfin))\\b', 'Pausing Jellyfin, {user_title}.', NULL, 'action', 7, 1),
|
||||||
|
|
||||||
|
-- DO server
|
||||||
|
('do_status', '(?i)\\b(do (server|status)|digital ocean (status|server)|vps status)\\b', 'Digital Ocean server is {do_status}, {user_title}.', 'do_server', 'response', 7, 1),
|
||||||
|
|
||||||
|
-- Focus / panels
|
||||||
|
('focus_mode', '(?i)\\b(focus (mode|on)|enable focus|concentration mode)\\b', 'Enabling focus mode, {user_title}.', NULL, 'action', 6, 1),
|
||||||
|
('show_panels', '(?i)\\b(show (all )?panels|expand (all|everything)|full view)\\b', 'Expanding all panels, {user_title}.', NULL, 'action', 6, 1),
|
||||||
|
|
||||||
|
-- Help
|
||||||
|
('help', '(?i)^(help|what can you do|commands|capabilities|what do you know)\\s*\\??$', 'I can help you with: system status, network status, VM/Proxmox status, Ollama AI models, site health, tasks and planner briefings, Jellyfin media, Home Assistant lights and devices, and general questions via Ollama. What would you like to know, {user_title}?', NULL, 'response', 5, 1)
|
||||||
|
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
pattern = VALUES(pattern),
|
||||||
|
response_template = VALUES(response_template),
|
||||||
|
active = 1;
|
||||||
|
|
||||||
|
SELECT COUNT(*) AS intents_seeded FROM kb_intents;
|
||||||
|
SELECT COUNT(*) AS prefs_seeded FROM kb_preferences;
|
||||||
@@ -242,7 +242,9 @@ if ($action) {
|
|||||||
$search = strtolower(trim($_GET['search'] ?? ''));
|
$search = strtolower(trim($_GET['search'] ?? ''));
|
||||||
$skipDomains = ['sensor','binary_sensor','button','update','select','number',
|
$skipDomains = ['sensor','binary_sensor','button','update','select','number',
|
||||||
'device_tracker','event','image','person','zone','tts','conversation',
|
'device_tracker','event','image','person','zone','tts','conversation',
|
||||||
'assist_satellite','input_button'];
|
'assist_satellite','input_button','media_player','scene','water_heater',
|
||||||
|
'alarm_control_panel','automation','script','calendar','notify',
|
||||||
|
'weather','camera','siren','remote','todo','lawn_mower'];
|
||||||
$skipKeywords = ['pre_release','_record','_ftp_','_push_','_hub_ringtone',
|
$skipKeywords = ['pre_release','_record','_ftp_','_push_','_hub_ringtone',
|
||||||
'_siren_on','_email_on','_manual_record','_infrared_',
|
'_siren_on','_email_on','_manual_record','_infrared_',
|
||||||
'do_not_disturb','matter_server','zerotier','mariadb',
|
'do_not_disturb','matter_server','zerotier','mariadb',
|
||||||
|
|||||||
Reference in New Issue
Block a user