BuddAI/run_buddai.ps1
JamesTheGiblet fc603464ee Add BuddAI local launcher script and ngrok integration
- Introduced `run_buddai.ps1` to automate the setup and launch of the BuddAI server.
- Implemented checks for Docker and Ollama services, ensuring they are running before starting the server.
- Added model verification and automatic pulling of required AI models.
- Created a Python virtual environment and installed necessary dependencies.
- Configured firewall rules for port 8000 and provided options for remote access via ngrok or Tailscale.
- Enhanced user experience with informative messages and QR code generation for easy access to the server.
- Included logic to determine the best public URL for the server based on available network configurations.
2025-12-30 00:15:54 +00:00

167 lines
No EOL
7.3 KiB
PowerShell

Write-Host 'BuddAI Local Launcher' -ForegroundColor Cyan
# Ensure execution happens in the script's directory
Set-Location $PSScriptRoot
# 1. Stop Docker if it's running to free up port 8000
if (Get-Command docker-compose -ErrorAction SilentlyContinue) {
Write-Host 'Ensuring Docker is stopped...' -ForegroundColor Yellow
docker-compose down 2>$null
}
# 2. Check Ollama Status
if (Get-Command ollama -ErrorAction SilentlyContinue) {
if (-not (Get-Process ollama* -ErrorAction SilentlyContinue)) {
Write-Host 'Ollama is not running. Starting...' -ForegroundColor Yellow
Start-Process ollama -ArgumentList "serve" -WindowStyle Hidden
Start-Sleep -Seconds 5
} else {
Write-Host 'Ollama is running.' -ForegroundColor Green
}
}
# 3. Check Models
if (Get-Command ollama -ErrorAction SilentlyContinue) {
Write-Host 'Checking AI models...' -ForegroundColor Green
$models = ollama list | Out-String
$required = @('qwen2.5-coder:1.5b', 'qwen2.5-coder:3b')
foreach ($model in $required) {
if ($models -notmatch [regex]::Escape($model)) {
Write-Host "Model '$model' missing. Pulling (this may take a while)..." -ForegroundColor Yellow
ollama pull $model
}
}
}
# 4. Create Virtual Environment if missing
if (-not (Test-Path 'venv')) {
Write-Host 'Creating Python virtual environment...' -ForegroundColor Green
python -m venv venv
}
# 5. Install Dependencies
Write-Host 'Checking dependencies...' -ForegroundColor Green
# Upgrade pip first to fix potential "Request-sent" or SSL errors
./venv/Scripts/python.exe -m pip install --upgrade pip
./venv/Scripts/python.exe -m pip install -r requirements.txt
if ($LASTEXITCODE -ne 0) {
Write-Host "Dependency installation failed." -ForegroundColor Red
exit
}
# 6. Run Server
Write-Host 'Starting BuddAI Server...' -ForegroundColor Cyan
# Get LAN IP for local network access
$lanIp = (Get-NetIPConfiguration | Where-Object { $_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.Status -eq "Up" }).IPv4Address.IPAddress | Select-Object -First 1
Write-Host " Local PC: http://localhost:8000/web" -ForegroundColor Gray
Write-Host " On Phone: http://$($lanIp):8000/web" -ForegroundColor Green
# Check for Tailscale (Private VPN)
# Try multiple methods to detect Tailscale IP
$tailscaleIp = (Get-NetIPAddress -InterfaceAlias "*Tailscale*" -AddressFamily IPv4 -ErrorAction SilentlyContinue).IPAddress | Select-Object -First 1
if (-not $tailscaleIp) {
# Fallback: Look for any IP in the 100.x.x.x range (Tailscale uses CGNAT 100.64.0.0/10)
$tailscaleIp = (Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object { $_.IPAddress -like "100.*" -and $_.InterfaceAlias -notlike "*Loopback*" }).IPAddress | Select-Object -First 1
}
if ($tailscaleIp) {
Write-Host " Tailscale: http://$($tailscaleIp):8000/web (Secure VPN)" -ForegroundColor Magenta
} elseif (Get-Service "Tailscale" -ErrorAction SilentlyContinue) {
Write-Host " Tailscale: Installed but not connected. Open app to log in." -ForegroundColor Yellow
} else {
Write-Host " Tailscale: (Optional) Run 'winget install Tailscale.Tailscale' for VPN access" -ForegroundColor DarkGray
}
# Attempt to open Firewall for LAN/VPN access
if (-not (Get-NetFirewallRule -DisplayName "BuddAI Allow Port 8000" -ErrorAction SilentlyContinue)) {
try {
New-NetFirewallRule -DisplayName "BuddAI Allow Port 8000" -Direction Inbound -LocalPort 8000 -Protocol TCP -Action Allow -ErrorAction Stop | Out-Null
Write-Host " [+] Firewall rule added for Port 8000" -ForegroundColor DarkGray
} catch {
Write-Host " [!] Firewall rule missing. Remote access will be blocked." -ForegroundColor Red
Write-Host " [?] Press 'A' to restart as Administrator to fix, or any key to continue..." -NoNewline -ForegroundColor Yellow
if ([Console]::ReadKey($true).Key -eq 'A') {
Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
exit
}
Write-Host ""
}
}
# Check for ngrok (Global or Local)
$ngrokPath = $null
$publicUrl = ""
if (Test-Path ".\ngrok.exe") {
$ngrokPath = (Resolve-Path ".\ngrok.exe").Path
} elseif (Get-Command ngrok -ErrorAction SilentlyContinue) {
$ngrokPath = "ngrok"
}
if ($ngrokPath -and -not $tailscaleIp) {
Write-Host " Remote: Run '$ngrokPath http 8000' for public access" -ForegroundColor DarkGray
Write-Host " [?] Press 'N'/'S' for Ngrok, or any key to skip (3s)..." -NoNewline -ForegroundColor Yellow
$timer = [System.Diagnostics.Stopwatch]::StartNew()
while ($timer.Elapsed.TotalSeconds -lt 3) {
if ([Console]::KeyAvailable) {
$key = [Console]::ReadKey($true).Key
if ($key -eq 'N' -or $key -eq 'S') {
$ngrokArgs = "http 8000"
if ($key -eq 'S') {
$ngrokArgs += " --basic-auth=`"admin:buddai`""
Write-Host "`n Launching Ngrok (Secure: admin/buddai)..." -ForegroundColor Green
} else {
Write-Host "`n Launching Ngrok (Public)..." -ForegroundColor Green
}
Start-Process $ngrokPath -ArgumentList $ngrokArgs -WindowStyle Hidden
# Retry loop to fetch URL (up to 15s)
$url = $null
Write-Host " Waiting for tunnel..." -NoNewline -ForegroundColor DarkGray
for ($i = 0; $i -lt 15; $i++) {
Start-Sleep -Seconds 1
try {
$tunnels = Invoke-RestMethod -Uri "http://localhost:4040/api/tunnels" -ErrorAction Stop
if ($tunnels.tunnels.Count -gt 0) { $url = $tunnels.tunnels[0].public_url; break }
} catch {}
Write-Host "." -NoNewline -ForegroundColor DarkGray
}
Write-Host ""
if ($url) {
$publicUrl = $url
Write-Host " Remote URL: $url" -ForegroundColor Cyan
Write-Host " Scan QR Code:" -ForegroundColor Gray
$qrScript = "import sys, qrcode; qr = qrcode.QRCode(); qr.add_data(sys.argv[1]); qr.print_ascii(invert=True)"
& ./venv/Scripts/python.exe -c $qrScript $url 2>$null
} else {
Write-Host " Ngrok running. Check http://localhost:4040 for URL" -ForegroundColor Yellow
}
} else {
Write-Host "`n Skipping Ngrok..." -ForegroundColor DarkGray
}
break
}
Start-Sleep -Milliseconds 50
}
Write-Host ""
} elseif ($ngrokPath) {
Write-Host " Remote: Ngrok available (Skipped due to Tailscale)" -ForegroundColor DarkGray
} else {
Write-Host " Remote: (Optional) Run 'winget install Ngrok.Ngrok' to enable remote access" -ForegroundColor DarkGray
}
# Determine best URL for the server to know about
if (-not $publicUrl -and $tailscaleIp) {
$publicUrl = "http://$($tailscaleIp):8000/web"
} elseif (-not $publicUrl) {
$publicUrl = "http://$($lanIp):8000/web"
}
Write-Host ' Opening browser...' -ForegroundColor DarkGray
Start-Process 'http://localhost:8000/'
# Use --host 0.0.0.0 to allow connections from other devices
./venv/Scripts/python.exe main.py --server --port 8000 --host 0.0.0.0 --public-url "$publicUrl"