diff --git a/README.md b/README.md index 16a65bd0d..7b9d90f36 100644 --- a/README.md +++ b/README.md @@ -106,10 +106,16 @@ Choose your preferred models and providers based on your requirements and prefer Launch the complete application stack (frontend, backend, and agents): +### Linux / Macos ```bash bash start.sh ``` +### Windows (PowerShell) +```powershell +.\start.ps1 +``` + ## Accessing the Interface - **Web UI**: Navigate to [http://localhost:1420](http://localhost:1420) in your browser diff --git a/python/scripts/launch.py b/python/scripts/launch.py index 556da446b..572baca6b 100644 --- a/python/scripts/launch.py +++ b/python/scripts/launch.py @@ -37,22 +37,27 @@ PROJECT_DIR = Path(__file__).resolve().parent.parent.parent PYTHON_DIR = PROJECT_DIR / "python" ENV_PATH = PROJECT_DIR / ".env" -ENV_PATH_STR = str(ENV_PATH.resolve()) + +# Convert paths to POSIX format (forward slashes) for cross-platform compatibility +# as_posix() works on both Windows and Unix systems +PROJECT_DIR_STR = PROJECT_DIR.as_posix() +PYTHON_DIR_STR = PYTHON_DIR.as_posix() +ENV_PATH_STR = ENV_PATH.as_posix() # Mapping from agent name to launch command MAP_NAME_COMMAND: Dict[str, str] = {} for name, analyst in MAP_NAME_ANALYST.items(): MAP_NAME_COMMAND[name] = ( - f"cd {PYTHON_DIR}/third_party/ai-hedge-fund && uv run --env-file {ENV_PATH} -m adapter --analyst {analyst}" + f"cd {PYTHON_DIR_STR}/third_party/ai-hedge-fund && uv run --env-file {ENV_PATH_STR} -m adapter --analyst {analyst}" ) MAP_NAME_COMMAND[SEC_AGENT_NAME] = ( - f"uv run --env-file {ENV_PATH} -m valuecell.agents.sec_agent" + f"uv run --env-file {ENV_PATH_STR} -m valuecell.agents.sec_agent" ) MAP_NAME_COMMAND[TRADING_AGENTS_NAME] = ( - f"cd {PYTHON_DIR}/third_party/TradingAgents && uv run --env-file {ENV_PATH} -m adapter" + f"cd {PYTHON_DIR_STR}/third_party/TradingAgents && uv run --env-file {ENV_PATH_STR} -m adapter" ) BACKEND_COMMAND = ( - f"cd {PYTHON_DIR} && uv run --env-file {ENV_PATH} -m valuecell.server.main" + f"cd {PYTHON_DIR_STR} && uv run --env-file {ENV_PATH_STR} -m valuecell.server.main" ) FRONTEND_URL = "http://localhost:1420" @@ -69,7 +74,7 @@ def check_envfile_is_set(): def main(): check_envfile_is_set() timestamp = datetime.now().strftime("%Y%m%d%H%M%S") - log_dir = f"{PROJECT_DIR}/logs/{timestamp}" + log_dir = f"{PROJECT_DIR_STR}/logs/{timestamp}" # Use questionary multi-select to allow choosing multiple agents selected_agents = questionary.checkbox( diff --git a/python/scripts/prepare_envs.ps1 b/python/scripts/prepare_envs.ps1 new file mode 100644 index 000000000..3fa879dc7 --- /dev/null +++ b/python/scripts/prepare_envs.ps1 @@ -0,0 +1,111 @@ +# PowerShell script to prepare Python environments +# Equivalent to prepare_envs.sh + +$ErrorActionPreference = "Stop" + +# Color output functions +function Write-Highlight($message) { + Write-Host $message -ForegroundColor Blue +} + +function Write-Success($message) { + Write-Host $message -ForegroundColor Green +} + +function Write-Warn($message) { + Write-Host $message -ForegroundColor Yellow +} + +function Write-Err($message) { + Write-Host $message -ForegroundColor Red +} + +function Highlight-Command($command) { + Write-Highlight "Running: $command" +} + +# Check current directory and switch to python if needed +$currentPath = Get-Location +if ((Test-Path "python") -and (Test-Path "python\pyproject.toml") -and (Test-Path ".gitignore")) { + Write-Warn "Detected project root. Switching to python directory..." + Set-Location "python" +} elseif (-not (Test-Path "pyproject.toml") -or -not (Test-Path "third_party")) { + Write-Err "Error: This script must be run from the project python directory or project root. You are in $currentPath" + exit 1 +} + +# Final check if in python directory +if (-not (Test-Path "pyproject.toml") -or -not (Test-Path "third_party")) { + Write-Err "Error: Failed to switch to python directory. You are in $(Get-Location)" + exit 1 +} + +# Check if uv is installed +if (-not (Get-Command "uv" -ErrorAction SilentlyContinue)) { + Write-Err "Error: 'uv' command not found. Please install 'uv' from https://docs.astral.sh/uv/" + exit 1 +} + +Write-Highlight "==========================================" +Write-Highlight "Starting environment preparation..." +Write-Highlight "==========================================" + +# Prepare main environment +Write-Success "Project root confirmed. Preparing environments..." + +Write-Warn "Setting up main Python environment..." +if (-not (Test-Path ".venv")) { + Highlight-Command "uv venv --python 3.12" + uv venv --python 3.12 +} else { + Write-Warn ".venv already exists, skipping venv creation." +} +Highlight-Command "uv sync --group dev" +uv sync --group dev +Write-Success "Main environment setup complete." + +Write-Highlight "==========================================" +Write-Highlight "Setting up third-party environments..." +Write-Highlight "==========================================" + +# Setup ai-hedge-fund environment +Write-Warn "Setting up ai-hedge-fund environment..." +Push-Location ".\third_party\ai-hedge-fund" +try { + if (-not (Test-Path ".venv")) { + Highlight-Command "uv venv --python 3.12" + uv venv --python 3.12 + } else { + Write-Warn ".venv already exists, skipping venv creation." + } + Highlight-Command "uv sync" + uv sync + Write-Success "ai-hedge-fund environment setup complete." +} finally { + Pop-Location +} + +Write-Warn "------------------------------------------" +Write-Warn "Setting up TradingAgents environment..." +Write-Warn "------------------------------------------" + +# Setup TradingAgents environment +Push-Location ".\third_party\TradingAgents" +try { + if (-not (Test-Path ".venv")) { + Highlight-Command "uv venv --python 3.12" + uv venv --python 3.12 + } else { + Write-Warn ".venv already exists, skipping venv creation." + } + Highlight-Command "uv sync" + uv sync + Write-Success "TradingAgents environment setup complete." +} finally { + Pop-Location +} + +Write-Success "==========================================" +Write-Success "All environments are set up." +Write-Success "==========================================" + diff --git a/start.ps1 b/start.ps1 new file mode 100644 index 000000000..46596ac2b --- /dev/null +++ b/start.ps1 @@ -0,0 +1,266 @@ +# Simple project launcher with auto-install for bun and uv +# - Windows: uses PowerShell installation scripts +# - Supports --no-frontend, --no-backend, -h/--help options + +param( + [switch]$NoFrontend, + [switch]$NoBackend, + [Alias("h")] + [switch]$Help +) + +$ErrorActionPreference = "Stop" + +$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path +$FRONTEND_DIR = Join-Path $SCRIPT_DIR "frontend" +$PY_DIR = Join-Path $SCRIPT_DIR "python" + +$BACKEND_PROCESS = $null +$FRONTEND_PROCESS = $null + +# Color output functions +function Write-Info($message) { + Write-Host "[INFO] $message" -ForegroundColor Cyan +} + +function Write-Success($message) { + Write-Host "[ OK ] $message" -ForegroundColor Green +} + +function Write-Warn($message) { + Write-Host "[WARN] $message" -ForegroundColor Yellow +} + +function Write-Err($message) { + Write-Host "[ERR ] $message" -ForegroundColor Red +} + +function Test-CommandExists($command) { + $null -ne (Get-Command $command -ErrorAction SilentlyContinue) +} + +function Ensure-Tool($toolName) { + if (Test-CommandExists $toolName) { + try { + $version = & $toolName --version 2>$null | Select-Object -First 1 + if (-not $version) { $version = "version unknown" } + Write-Success "$toolName is installed ($version)" + } catch { + Write-Success "$toolName is installed" + } + return + } + + Write-Info "Installing $toolName..." + + if ($toolName -eq "bun") { + # Install bun on Windows using PowerShell script + try { + Write-Info "Installing bun via PowerShell script..." + # Use a new PowerShell process to avoid variable conflicts + $installCmd = "irm https://bun.sh/install.ps1 | iex" + powershell.exe -NoProfile -ExecutionPolicy Bypass -Command $installCmd + + # Add to PATH for current session + $bunPath = "$env:USERPROFILE\.bun\bin" + if (Test-Path $bunPath) { + $env:Path = "$bunPath;$env:Path" + } + } catch { + Write-Err "Failed to install bun: $_" + Write-Err "Please install manually from https://bun.sh/docs/installation" + exit 1 + } + } elseif ($toolName -eq "uv") { + # Install uv on Windows using PowerShell script + try { + Write-Info "Installing uv via PowerShell script..." + # Use a new PowerShell process to avoid variable conflicts + $installCmd = "irm https://astral.sh/uv/install.ps1 | iex" + powershell.exe -NoProfile -ExecutionPolicy Bypass -Command $installCmd + + # Add to PATH for current session - check multiple possible locations + $possiblePaths = @( + "$env:USERPROFILE\.cargo\bin", + "$env:USERPROFILE\.local\bin", + "$env:LOCALAPPDATA\Programs\uv" + ) + foreach ($uvPath in $possiblePaths) { + if (Test-Path $uvPath) { + $env:Path = "$uvPath;$env:Path" + break + } + } + } catch { + Write-Err "Failed to install uv: $_" + Write-Err "Please install manually from https://docs.astral.sh/uv/getting-started/installation/" + exit 1 + } + } else { + Write-Warn "Unknown tool: $toolName" + exit 1 + } + + # Verify installation + if (Test-CommandExists $toolName) { + Write-Success "$toolName installed successfully" + } else { + Write-Err "$toolName installation failed. Please install manually and retry." + Write-Err "You may need to restart your terminal or add the tool to your PATH." + exit 1 + } +} + +function Compile { + # Backend deps + if (Test-Path $PY_DIR) { + Write-Info "Sync Python dependencies (uv sync)..." + Push-Location $PY_DIR + try { + # Run prepare environments script + if (Test-Path "scripts\prepare_envs.ps1") { + Write-Info "Running environment preparation script..." + & ".\scripts\prepare_envs.ps1" + } else { + Write-Warn "prepare_envs.ps1 not found, running uv sync directly..." + uv sync + } + uv run valuecell/server/db/init_db.py + Write-Success "Python dependencies synced" + } catch { + Write-Err "Failed to sync Python dependencies: $_" + exit 1 + } finally { + Pop-Location + } + } else { + Write-Warn "Backend directory not found: $PY_DIR. Skipping" + } + + # Frontend deps + if (Test-Path $FRONTEND_DIR) { + Write-Info "Install frontend dependencies (bun install)..." + Push-Location $FRONTEND_DIR + try { + bun install + Write-Success "Frontend dependencies installed" + } catch { + Write-Err "Failed to install frontend dependencies: $_" + exit 1 + } finally { + Pop-Location + } + } else { + Write-Warn "Frontend directory not found: $FRONTEND_DIR. Skipping" + } +} + +function Start-Backend { + if (-not (Test-Path $PY_DIR)) { + Write-Warn "Backend directory not found; skipping backend start" + return + } + + Write-Info "Starting backend (uv run scripts/launch.py)..." + Write-Info "Launching in CMD for better interactive terminal support..." + + # Use cmd.exe for better interactive support with questionary + # CMD handles ANSI escape sequences and arrow keys better than PowerShell + $launchCmd = "cd /d `"$PY_DIR`" && uv run --with questionary --with colorama scripts/launch.py" + Start-Process "cmd.exe" -ArgumentList "/k", $launchCmd -Wait +} + +function Start-Frontend { + if (-not (Test-Path $FRONTEND_DIR)) { + Write-Warn "Frontend directory not found; skipping frontend start" + return + } + + Write-Info "Starting frontend dev server (bun run dev)..." + Push-Location $FRONTEND_DIR + try { + $script:FRONTEND_PROCESS = Start-Process -FilePath "bun" -ArgumentList "run", "dev" -NoNewWindow -PassThru + Write-Info "Frontend PID: $($script:FRONTEND_PROCESS.Id)" + } catch { + Write-Err "Failed to start frontend: $_" + } finally { + Pop-Location + } +} + +function Cleanup { + Write-Host "" + Write-Info "Stopping services..." + + if ($script:FRONTEND_PROCESS -and -not $script:FRONTEND_PROCESS.HasExited) { + try { + Stop-Process -Id $script:FRONTEND_PROCESS.Id -Force -ErrorAction SilentlyContinue + } catch { + # Ignore errors + } + } + + if ($script:BACKEND_PROCESS -and -not $script:BACKEND_PROCESS.HasExited) { + try { + Stop-Process -Id $script:BACKEND_PROCESS.Id -Force -ErrorAction SilentlyContinue + } catch { + # Ignore errors + } + } + + Write-Success "Stopped" +} + +function Print-Usage { + Write-Host @" +Usage: .\start.ps1 [options] + +Description: + - Checks whether bun and uv are installed; missing tools will be auto-installed via PowerShell scripts. + - Then installs backend and frontend dependencies and starts services. + +Options: + -NoFrontend Start backend only + -NoBackend Start frontend only + -Help, -h Show this help message +"@ +} + +# Handle Ctrl+C and cleanup +Register-EngineEvent PowerShell.Exiting -Action { Cleanup } | Out-Null +try { + # Show help if requested + if ($Help) { + Print-Usage + exit 0 + } + + # Ensure tools are installed + Ensure-Tool "bun" + Ensure-Tool "uv" + + # Compile/install dependencies + Compile + + # Start services based on flags + if (-not $NoFrontend) { + Start-Frontend + Start-Sleep -Seconds 5 # Give frontend a moment to start + } + + if (-not $NoBackend) { + Start-Backend + } + + # If frontend is running, wait for it + if ($script:FRONTEND_PROCESS -and -not $script:FRONTEND_PROCESS.HasExited) { + Write-Info "Services running. Press Ctrl+C to stop..." + Wait-Process -Id $script:FRONTEND_PROCESS.Id -ErrorAction SilentlyContinue + } +} catch { + Write-Err "An error occurred: $_" + exit 1 +} finally { + Cleanup +} +