Feat/add developer docs for windows (#213)

* docs: add windows commands for developer setup

* feat: add windows scripts

* fix(ui): make dev script cross-platform with cross-env

* feat(scripts): enhance migration scripts for Alembic environment setup and add virtual environment activation
This commit is contained in:
Muhammad Qasim 2026-04-03 06:34:13 +05:00 committed by GitHub
parent e7adbc7bad
commit 66b085dde2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 443 additions and 13 deletions

58
scripts/makemigrate.ps1 Normal file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env pwsh
# Create a new Alembic migration with autogenerate (Windows)
Param(
[string]$MigrationName,
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$BaseDir = Split-Path -Parent $ScriptDir
Set-Location $BaseDir
# Ensure repository root is importable for Alembic env/module resolution.
if ($env:PYTHONPATH) {
$env:PYTHONPATH = "$BaseDir;$($env:PYTHONPATH)"
} else {
$env:PYTHONPATH = $BaseDir
}
$EnvFile = Join-Path $BaseDir 'api/.env'
# Load environment variables
if (Test-Path $EnvFile) {
Get-Content $EnvFile | ForEach-Object {
$line = $_.Trim()
if ($line -and -not $line.StartsWith('#')) {
$parts = $line -split '=', 2
if ($parts.Count -eq 2) {
[Environment]::SetEnvironmentVariable($parts[0].Trim(), $parts[1].Trim().Trim('"'), 'Process')
}
}
}
} else {
Write-Host "Error: Environment file $EnvFile not found." -ForegroundColor Red
exit 1
}
# Prompt for migration name when not provided via parameter
if (-not $MigrationName) {
$MigrationName = Read-Host "Enter the migration name (minimum 5 characters)"
}
if (-not $MigrationName -or $MigrationName.Length -lt 5) {
Write-Host "Error: Migration name must be at least 5 characters long." -ForegroundColor Red
exit 1
}
# Generate the Alembic revision
$cmd = "alembic -c api/alembic.ini revision --autogenerate -m `"$MigrationName`""
if ($DryRun) {
Write-Host "Dry run: $cmd"
exit 0
}
alembic -c api/alembic.ini revision --autogenerate -m $MigrationName

36
scripts/migrate.ps1 Normal file
View file

@ -0,0 +1,36 @@
#!/usr/bin/env pwsh
# Run Alembic database migrations (Windows)
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$BaseDir = Split-Path -Parent $ScriptDir
Set-Location $BaseDir
# Ensure repository root is importable for Alembic env/module resolution.
if ($env:PYTHONPATH) {
$env:PYTHONPATH = "$BaseDir;$($env:PYTHONPATH)"
} else {
$env:PYTHONPATH = $BaseDir
}
$EnvFile = Join-Path $BaseDir 'api/.env'
# Load environment variables
if (Test-Path $EnvFile) {
Get-Content $EnvFile | ForEach-Object {
$line = $_.Trim()
if ($line -and -not $line.StartsWith('#')) {
$parts = $line -split '=', 2
if ($parts.Count -eq 2) {
[Environment]::SetEnvironmentVariable($parts[0].Trim(), $parts[1].Trim().Trim('"'), 'Process')
}
}
}
} else {
Write-Host "Error: Environment file $EnvFile not found." -ForegroundColor Red
exit 1
}
# Run migrations
alembic -c api/alembic.ini upgrade head

24
scripts/setup_pipecat.ps1 Normal file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env pwsh
# Setup script for using pipecat as a git submodule (Windows)
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$BaseDir = Split-Path -Parent $ScriptDir
Set-Location $BaseDir
Write-Host "Setting up pipecat as a git submodule..."
# Initialize and update submodules
Write-Host "Initializing git submodules..."
git submodule update --init --recursive
# Install pipecat in editable mode with all extras
Write-Host "Installing pipecat dependencies..."
pip install -e './pipecat[cartesia,deepgram,openai,elevenlabs,groq,google,azure,sarvam,soundfile,silero,webrtc,speechmatics,openrouter,camb]'
# Install other requirements
Write-Host "Installing dograh API requirements..."
pip install -r api/requirements.txt
Write-Host "Setup complete! Pipecat is now available as a git submodule."

View file

@ -0,0 +1,151 @@
#!/usr/bin/env pwsh
# Start Dograh services in development mode (Windows)
# Usage: .\scripts\start_services_dev.ps1 [-ArqWorkers 2] [-NoMigrations] [-IncludeTelephonyWorkers]
#
# Note: Telephony workers (ari_manager, campaign_orchestrator) are disabled by
# default on Windows because they use Unix signal handlers not supported by the
# Windows asyncio event loop.
Param(
[int]$ArqWorkers = 1,
[switch]$NoMigrations,
[switch]$IncludeTelephonyWorkers
)
$ErrorActionPreference = 'Stop'
###############################################################################
### CONFIGURATION
###############################################################################
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$BaseDir = Split-Path -Parent $ScriptDir
Set-Location $BaseDir
$EnvFile = Join-Path $BaseDir 'api/.env'
$RunDir = Join-Path $BaseDir 'run'
$LogsRoot = Join-Path $BaseDir 'logs'
$LatestDir = Join-Path $LogsRoot 'latest'
$VenvPath = Join-Path $BaseDir 'venv'
Write-Host "Starting Dograh Services (DEV MODE) in BASE_DIR: $BaseDir"
Write-Host "Auto-reload enabled for api/ directory changes"
###############################################################################
### 1) Load environment variables
###############################################################################
if (Test-Path $EnvFile) {
Get-Content $EnvFile | ForEach-Object {
$line = $_.Trim()
if ($line -and -not $line.StartsWith('#')) {
$parts = $line -split '=', 2
if ($parts.Count -eq 2) {
[Environment]::SetEnvironmentVariable($parts[0].Trim(), $parts[1].Trim().Trim('"'), 'Process')
}
}
}
}
if (-not $env:UVICORN_BASE_PORT) { $env:UVICORN_BASE_PORT = '8000' }
###############################################################################
### 2) Define services
###############################################################################
$serviceSpecs = @()
if ($IncludeTelephonyWorkers) {
$serviceSpecs += @{ Name = 'ari_manager'; Cmd = "python -m api.services.telephony.ari_manager" }
$serviceSpecs += @{ Name = 'campaign_orchestrator'; Cmd = "python -m api.services.campaign.campaign_orchestrator" }
}
$serviceSpecs += @{ Name = 'uvicorn'; Cmd = "uvicorn api.app:app --host 0.0.0.0 --port $($env:UVICORN_BASE_PORT) --reload --reload-dir api" }
for ($i = 1; $i -le $ArqWorkers; $i++) {
$serviceSpecs += @{ Name = "arq$i"; Cmd = "python -m arq api.tasks.arq.WorkerSettings --custom-log-dict api.tasks.arq.LOG_CONFIG" }
}
###############################################################################
### 3) Activate virtual environment
###############################################################################
$VenvActivateScript = Join-Path $VenvPath 'Scripts/Activate.ps1'
if (Test-Path $VenvActivateScript) {
. $VenvActivateScript
Write-Host "Virtual environment activated: $VenvPath"
} else {
Write-Host "Warning: Virtual environment not found at $VenvPath"
Write-Host "Continuing without virtual environment activation..."
}
###############################################################################
### 4) Stop old services
###############################################################################
New-Item -ItemType Directory -Path $RunDir -Force | Out-Null
foreach ($spec in $serviceSpecs) {
$pidFile = Join-Path $RunDir "$($spec.Name).pid"
if (Test-Path $pidFile) {
$oldPid = (Get-Content $pidFile -Raw).Trim()
if ($oldPid) {
$prev = $ErrorActionPreference; $ErrorActionPreference = 'SilentlyContinue'
& taskkill /PID $oldPid /T /F 2>&1 | Out-Null
$ErrorActionPreference = $prev
}
Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
}
}
###############################################################################
### 5) Run migrations
###############################################################################
if (-not $NoMigrations) {
alembic -c (Join-Path $BaseDir 'api/alembic.ini') upgrade head
}
###############################################################################
### 6) Prepare logs
###############################################################################
New-Item -ItemType Directory -Path $LatestDir -Force | Out-Null
Get-ChildItem $LatestDir -Filter '*.log' -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
###############################################################################
### 7) Start services
###############################################################################
foreach ($spec in $serviceSpecs) {
$name = $spec.Name
$logPath = Join-Path $LatestDir "$name.log"
$pidFile = Join-Path $RunDir "$name.pid"
Write-Host "-> Starting $name"
$wrapped = "cd /d `"$BaseDir`" && $($spec.Cmd) >> `"$logPath`" 2>&1"
$proc = Start-Process cmd.exe -ArgumentList '/c', $wrapped -PassThru -WindowStyle Hidden
Set-Content -Path $pidFile -Value $proc.Id
Write-Host " PID $($proc.Id) -> $logPath"
}
###############################################################################
### 8) Summary
###############################################################################
Write-Host ""
Write-Host "------------------------------------------------------"
Write-Host "Mode: DEVELOPMENT (auto-reload enabled)"
Write-Host ""
foreach ($spec in $serviceSpecs) {
$procId = (Get-Content (Join-Path $RunDir "$($spec.Name).pid") -Raw).Trim()
Write-Host " $($spec.Name) (PID $procId) -> logs/latest/$($spec.Name).log"
}
Write-Host ""
Write-Host "Health: curl.exe http://localhost:$($env:UVICORN_BASE_PORT)/api/v1/health"
Write-Host "Logs: Get-Content logs/latest/*.log -Wait"
Write-Host "Stop: .\scripts\stop_services.ps1"
Write-Host "------------------------------------------------------"

92
scripts/stop_services.ps1 Normal file
View file

@ -0,0 +1,92 @@
#!/usr/bin/env pwsh
# Stop Dograh services started by start_services_dev.ps1 (Windows)
$ErrorActionPreference = 'Stop'
###############################################################################
### CONFIGURATION
###############################################################################
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$BaseDir = Split-Path -Parent $ScriptDir
$RunDir = Join-Path $BaseDir 'run'
Set-Location $BaseDir
Write-Host "Stopping Dograh Services in BASE_DIR: $BaseDir"
###############################################################################
### HELPER
###############################################################################
function Stop-ProcessTree([int]$ProcessId) {
# taskkill /T kills the entire process tree. Temporarily relax error
# preference so that a "process not found" message on stderr does not
# terminate the script.
$prev = $ErrorActionPreference
try {
$ErrorActionPreference = 'SilentlyContinue'
& taskkill /PID $ProcessId /T /F 2>&1 | Out-Null
} finally {
$ErrorActionPreference = $prev
}
}
###############################################################################
### STOP SERVICES
###############################################################################
if (-not (Test-Path $RunDir)) {
Write-Host "No run directory found at $RunDir"
Write-Host "No services appear to be running."
exit 0
}
$pidFiles = Get-ChildItem $RunDir -Filter '*.pid' -ErrorAction SilentlyContinue
if (-not $pidFiles) {
Write-Host "No PID files found in $RunDir"
Write-Host "No services appear to be running."
exit 0
}
$stoppedCount = 0
$failedCount = 0
foreach ($pidFile in $pidFiles) {
$name = $pidFile.BaseName
$oldPid = (Get-Content $pidFile.FullName -Raw).Trim()
$proc = Get-Process -Id ([int]$oldPid) -ErrorAction SilentlyContinue
if ($proc) {
Write-Host "Stopping $name (PID $oldPid)..."
Stop-ProcessTree ([int]$oldPid)
Start-Sleep -Seconds 2
$still = Get-Process -Id ([int]$oldPid) -ErrorAction SilentlyContinue
if ($still) {
Write-Host " Warning: $name did not exit cleanly"
$failedCount++
} else {
Write-Host " Stopped $name"
$stoppedCount++
}
} else {
# The tracked cmd.exe may have exited but child processes may still run.
# Best-effort cleanup via taskkill tree kill.
Stop-ProcessTree ([int]$oldPid)
Write-Host "Service $name (PID $oldPid) is not running"
}
Remove-Item $pidFile.FullName -Force -ErrorAction SilentlyContinue
}
###############################################################################
### SUMMARY
###############################################################################
Write-Host ""
Write-Host "------------------------------------------------------"
Write-Host "Stopped $stoppedCount service(s)"
if ($failedCount -gt 0) {
Write-Host "Failed to stop $failedCount service(s)"
}
Write-Host "------------------------------------------------------"