chore: Add Atomizer launcher and utility scripts

- atomizer.ico: Application icon
- launch_atomizer.bat: One-click launcher for dashboard
- create_desktop_shortcut.ps1: Desktop shortcut creator
- restart_backend.bat, start_backend_8002.bat: Dev utilities
This commit is contained in:
2026-01-20 13:12:12 -05:00
parent 6c30224341
commit cf8c57fdac
5 changed files with 294 additions and 0 deletions

14
restart_backend.bat Normal file
View File

@@ -0,0 +1,14 @@
@echo off
echo Killing processes on port 8001...
for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":8001.*LISTENING"') do (
echo Killing PID %%a
taskkill /F /PID %%a 2>nul
)
echo Waiting for port to free up...
ping 127.0.0.1 -n 3 >nul
echo Starting backend...
cd /d C:\Users\antoi\Atomizer\atomizer-dashboard\backend
call C:\Users\antoi\anaconda3\Scripts\activate.bat atomizer
python -m uvicorn api.main:app --port 8001

6
start_backend_8002.bat Normal file
View File

@@ -0,0 +1,6 @@
@echo off
title Atomizer Backend (Port 8002)
echo Starting Atomizer Backend on port 8002...
cd /d C:\Users\antoi\Atomizer\atomizer-dashboard\backend
call C:\Users\antoi\anaconda3\Scripts\activate.bat atomizer
python -m uvicorn api.main:app --port 8002 --reload

BIN
tools/atomizer.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,209 @@
# ============================================================
# Atomizer Desktop Shortcut Creator
# Creates a desktop shortcut with custom "A" icon
# ============================================================
$ErrorActionPreference = "Stop"
# Paths
$AtomizerRoot = Split-Path -Parent $PSScriptRoot
$ToolsDir = $PSScriptRoot
$IconPath = Join-Path $ToolsDir "atomizer.ico"
$LauncherPath = Join-Path $ToolsDir "launch_atomizer.bat"
$DesktopPath = [Environment]::GetFolderPath("Desktop")
$ShortcutPath = Join-Path $DesktopPath "Atomizer.lnk"
Write-Host ""
Write-Host " Atomizer Desktop Shortcut Creator" -ForegroundColor Cyan
Write-Host " ===================================" -ForegroundColor Cyan
Write-Host ""
# Step 1: Create ICO file with "A" letter
Write-Host "[1/3] Creating icon file..." -ForegroundColor Yellow
# Generate a simple ICO file using .NET
Add-Type -AssemblyName System.Drawing
function Create-AtomizerIcon {
param([string]$OutputPath)
# Create multiple icon sizes for best quality
$sizes = @(256, 48, 32, 16)
$bitmaps = @()
foreach ($size in $sizes) {
$bitmap = New-Object System.Drawing.Bitmap($size, $size)
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
# High quality rendering
$graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
$graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$graphics.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAliasGridFit
# Background - gradient blue (Atomizer brand color)
$brush = New-Object System.Drawing.Drawing2D.LinearGradientBrush(
(New-Object System.Drawing.Point(0, 0)),
(New-Object System.Drawing.Point($size, $size)),
[System.Drawing.Color]::FromArgb(255, 59, 130, 246), # Blue-500
[System.Drawing.Color]::FromArgb(255, 37, 99, 235) # Blue-600
)
# Rounded rectangle background
$path = New-Object System.Drawing.Drawing2D.GraphicsPath
$radius = [int]($size * 0.15)
$rect = New-Object System.Drawing.Rectangle(0, 0, $size, $size)
$path.AddArc($rect.X, $rect.Y, $radius * 2, $radius * 2, 180, 90)
$path.AddArc($rect.Right - $radius * 2, $rect.Y, $radius * 2, $radius * 2, 270, 90)
$path.AddArc($rect.Right - $radius * 2, $rect.Bottom - $radius * 2, $radius * 2, $radius * 2, 0, 90)
$path.AddArc($rect.X, $rect.Bottom - $radius * 2, $radius * 2, $radius * 2, 90, 90)
$path.CloseFigure()
$graphics.FillPath($brush, $path)
# Draw "A" letter
$fontSize = [int]($size * 0.65)
$font = New-Object System.Drawing.Font("Segoe UI", $fontSize, [System.Drawing.FontStyle]::Bold)
$textBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
$format = New-Object System.Drawing.StringFormat
$format.Alignment = [System.Drawing.StringAlignment]::Center
$format.LineAlignment = [System.Drawing.StringAlignment]::Center
$textRect = New-Object System.Drawing.RectangleF(0, 0, $size, $size)
$graphics.DrawString("A", $font, $textBrush, $textRect, $format)
# Cleanup
$graphics.Dispose()
$font.Dispose()
$textBrush.Dispose()
$brush.Dispose()
$path.Dispose()
$bitmaps += $bitmap
}
# Save as ICO (using the largest bitmap, Windows will auto-select appropriate size)
# For proper multi-size ICO, we'll save the 256x256 and let Windows handle it
$icon = [System.Drawing.Icon]::FromHandle($bitmaps[0].GetHicon())
# Write ICO file manually with all sizes
$fs = [System.IO.File]::Create($OutputPath)
$bw = New-Object System.IO.BinaryWriter($fs)
# ICO Header
$bw.Write([UInt16]0) # Reserved
$bw.Write([UInt16]1) # Type (1 = ICO)
$bw.Write([UInt16]$sizes.Count) # Number of images
# Calculate offsets
$headerSize = 6 + ($sizes.Count * 16) # Main header + directory entries
$currentOffset = $headerSize
$imageData = @()
# Prepare image data and write directory entries
for ($i = 0; $i -lt $sizes.Count; $i++) {
$bmp = $bitmaps[$i]
$ms = New-Object System.IO.MemoryStream
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
$pngBytes = $ms.ToArray()
$ms.Dispose()
$imageData += ,$pngBytes
# Directory entry
$width = if ($sizes[$i] -ge 256) { 0 } else { $sizes[$i] }
$height = if ($sizes[$i] -ge 256) { 0 } else { $sizes[$i] }
$bw.Write([byte]$width) # Width
$bw.Write([byte]$height) # Height
$bw.Write([byte]0) # Color palette
$bw.Write([byte]0) # Reserved
$bw.Write([UInt16]1) # Color planes
$bw.Write([UInt16]32) # Bits per pixel
$bw.Write([UInt32]$pngBytes.Length) # Image size
$bw.Write([UInt32]$currentOffset) # Offset
$currentOffset += $pngBytes.Length
}
# Write image data
foreach ($data in $imageData) {
$bw.Write($data)
}
$bw.Close()
$fs.Close()
# Cleanup bitmaps
foreach ($bmp in $bitmaps) {
$bmp.Dispose()
}
return $true
}
try {
Create-AtomizerIcon -OutputPath $IconPath
Write-Host " Created: $IconPath" -ForegroundColor Green
}
catch {
Write-Host " Warning: Could not create custom icon. Using default." -ForegroundColor Yellow
Write-Host " Error: $_" -ForegroundColor DarkGray
$IconPath = $null
}
# Step 2: Create desktop shortcut
Write-Host "[2/3] Creating desktop shortcut..." -ForegroundColor Yellow
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($ShortcutPath)
$Shortcut.TargetPath = $LauncherPath
$Shortcut.WorkingDirectory = $AtomizerRoot
$Shortcut.Description = "Launch Atomizer Optimization Dashboard"
$Shortcut.WindowStyle = 1 # Normal window
if ($IconPath -and (Test-Path $IconPath)) {
$Shortcut.IconLocation = "$IconPath,0"
}
$Shortcut.Save()
Write-Host " Created: $ShortcutPath" -ForegroundColor Green
# Step 3: Verify
Write-Host "[3/3] Verifying installation..." -ForegroundColor Yellow
$success = $true
if (-not (Test-Path $ShortcutPath)) {
Write-Host " ERROR: Shortcut not created!" -ForegroundColor Red
$success = $false
}
if (-not (Test-Path $LauncherPath)) {
Write-Host " ERROR: Launcher script missing!" -ForegroundColor Red
$success = $false
}
if ($success) {
Write-Host ""
Write-Host "============================================================" -ForegroundColor Green
Write-Host " SUCCESS! Atomizer shortcut created on your desktop." -ForegroundColor Green
Write-Host "============================================================" -ForegroundColor Green
Write-Host ""
Write-Host " Double-click 'Atomizer' on your desktop to launch!" -ForegroundColor White
Write-Host ""
Write-Host " What happens when you click:" -ForegroundColor Cyan
Write-Host " 1. Backend server starts (FastAPI on port 8000)" -ForegroundColor Gray
Write-Host " 2. Frontend server starts (Vite on port 5173)" -ForegroundColor Gray
Write-Host " 3. Browser opens to http://localhost:5173" -ForegroundColor Gray
Write-Host ""
Write-Host " To stop: Close the 'Atomizer Backend' and 'Atomizer Frontend'" -ForegroundColor Cyan
Write-Host " terminal windows." -ForegroundColor Cyan
Write-Host ""
}
else {
Write-Host ""
Write-Host "Installation had errors. Please check the messages above." -ForegroundColor Red
Write-Host ""
}
# Keep window open
Read-Host "Press Enter to close"

65
tools/launch_atomizer.bat Normal file
View File

@@ -0,0 +1,65 @@
@echo off
REM ============================================================
REM Atomizer Dashboard Launcher
REM One-click: starts servers and opens dashboard in browser
REM ============================================================
title Atomizer
cd /d "%~dp0\.."
REM Ports (match vite.config.ts)
set BACKEND_PORT=8001
set FRONTEND_PORT=3003
set URL=http://localhost:%FRONTEND_PORT%
REM Check if already running
set BACKEND_RUNNING=0
set FRONTEND_RUNNING=0
netstat -ano | findstr "LISTENING" | findstr ":%BACKEND_PORT% " > nul 2>&1
if %errorlevel% equ 0 set BACKEND_RUNNING=1
netstat -ano | findstr "LISTENING" | findstr ":%FRONTEND_PORT% " > nul 2>&1
if %errorlevel% equ 0 set FRONTEND_RUNNING=1
REM If both running, just open browser and exit immediately
if %BACKEND_RUNNING% equ 1 (
if %FRONTEND_RUNNING% equ 1 (
start "" %URL%
exit
)
)
REM Show brief splash while starting
echo.
echo Starting Atomizer Dashboard...
echo.
REM Start backend (hidden window)
if %BACKEND_RUNNING% equ 0 (
echo [1/2] Backend...
start /min "Atomizer Backend" cmd /c "cd /d %~dp0\..\atomizer-dashboard\backend && C:\Users\antoi\anaconda3\envs\atomizer\python.exe -m uvicorn api.main:app --host 0.0.0.0 --port %BACKEND_PORT%"
)
REM Start frontend (hidden window)
if %FRONTEND_RUNNING% equ 0 (
echo [2/2] Frontend...
start /min "Atomizer Frontend" cmd /c "cd /d %~dp0\..\atomizer-dashboard\frontend && npm run dev"
)
REM Wait for frontend to be ready (poll until port responds)
echo.
echo Waiting for servers to start...
:WAIT_LOOP
timeout /t 1 /nobreak > nul
netstat -ano | findstr "LISTENING" | findstr ":%FRONTEND_PORT% " > nul 2>&1
if %errorlevel% neq 0 goto WAIT_LOOP
REM Small extra delay to ensure Vite is fully ready
timeout /t 2 /nobreak > nul
REM Open browser
start "" %URL%
REM Close this launcher window
exit