mirror of
https://github.com/JamesTheGiblet/BuddAI.git
synced 2026-01-08 21:58:40 +00:00
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.
This commit is contained in:
parent
93c9395c6f
commit
fc603464ee
9 changed files with 851 additions and 88 deletions
167
run_buddai.ps1
Normal file
167
run_buddai.ps1
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue