Skip to content

Commit d534395

Browse files
feat: enhance dashboard command with auto-start and aiui integration
- Add auto-start functionality to dashboard command (default enabled) - Integrate aiui for enhanced dashboard interface (--aiui flag) - Auto-start Flow (7860), Claw (8082), and UI (8081) services - Add --no-auto-start flag for manual service management - Smart service detection to avoid conflicts - Robust error handling and logging to ~/.praisonai/unified/logs/ - Enhanced user experience with clear status messages - Graceful fallback when aiui not installed Fixes #1462 Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
1 parent 3ff9948 commit d534395

1 file changed

Lines changed: 182 additions & 6 deletions

File tree

src/praisonai/praisonai/cli/commands/unified.py

Lines changed: 182 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,163 @@ def _unregister_cleanup_handlers(original_sigint, original_sigterm):
7676
# so we keep the atexit handler but check if process list is empty
7777

7878

79+
def _auto_start_services(console, host: str):
80+
"""Auto-start PraisonAI services like the 'up' command does."""
81+
import os
82+
import sys
83+
84+
# Services to start
85+
services = [
86+
("flow", 7860),
87+
("claw", 8082),
88+
("ui", 8081)
89+
]
90+
91+
for service_name, service_port in services:
92+
# Check if service is already running
93+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
94+
check_host = "127.0.0.1" if host == "0.0.0.0" else host
95+
try:
96+
connection_result = sock.connect_ex((check_host, service_port))
97+
if connection_result == 0:
98+
console.print(f"[yellow]✓ {service_name} already running on port {service_port}[/yellow]")
99+
sock.close()
100+
continue
101+
except OSError:
102+
pass
103+
finally:
104+
sock.close()
105+
106+
# Start the service
107+
console.print(f"[cyan]Starting {service_name} on port {service_port}...[/cyan]")
108+
try:
109+
# Create log directory for troubleshooting
110+
log_dir = Path.home() / ".praisonai" / "unified" / "logs"
111+
log_dir.mkdir(parents=True, exist_ok=True)
112+
log_file = log_dir / f"{service_name}.log"
113+
114+
log_handle = open(log_file, "a", encoding="utf-8")
115+
try:
116+
if service_name == "flow":
117+
proc = subprocess.Popen([
118+
sys.executable, "-m", "praisonai", "flow",
119+
"--port", str(service_port), "--host", host, "--no-open"
120+
], stdout=log_handle, stderr=subprocess.STDOUT)
121+
elif service_name == "claw":
122+
proc = subprocess.Popen([
123+
sys.executable, "-m", "praisonai", "claw",
124+
"--port", str(service_port), "--host", host
125+
], stdout=log_handle, stderr=subprocess.STDOUT)
126+
elif service_name == "ui":
127+
proc = subprocess.Popen([
128+
sys.executable, "-m", "praisonai", "ui",
129+
"--port", str(service_port), "--host", host
130+
], stdout=log_handle, stderr=subprocess.STDOUT)
131+
132+
# Track process for cleanup
133+
_ACTIVE_PROCESSES.add(proc)
134+
_PROCESS_LOG_HANDLES[proc] = log_handle
135+
136+
# Wait briefly for service to start
137+
time.sleep(1.5)
138+
139+
# Check if process is still alive
140+
if proc.poll() is not None:
141+
console.print(f"[red]✗ {service_name} failed to start (exit code: {proc.returncode})[/red]")
142+
console.print(f"[dim]Check log: {log_file}[/dim]")
143+
# Clean up failed process
144+
_ACTIVE_PROCESSES.discard(proc)
145+
if proc in _PROCESS_LOG_HANDLES:
146+
_PROCESS_LOG_HANDLES.pop(proc).close()
147+
else:
148+
console.print(f"[green]✓ {service_name} started successfully[/green]")
149+
except Exception:
150+
log_handle.close()
151+
raise
152+
153+
except Exception as e:
154+
console.print(f"[red]✗ Failed to start {service_name}: {e}[/red]")
155+
156+
157+
def _run_aiui_dashboard(port: int, host: str, console):
158+
"""Run the aiui dashboard interface."""
159+
console.print("[bold green]🦞 Starting aiui Dashboard...[/bold green]")
160+
161+
try:
162+
# Try to import and run aiui directly
163+
import sys
164+
import tempfile
165+
import os
166+
167+
# Create a temporary script for aiui dashboard
168+
aiui_script = f'''
169+
import praisonaiui as aiui
170+
171+
# Configure aiui for dashboard style
172+
aiui.set_style("dashboard")
173+
aiui.set_branding(title="PraisonAI Unified Dashboard", logo="🌟")
174+
175+
# Set up pages for unified dashboard
176+
aiui.set_pages([
177+
"chat", "agents", "memory", "knowledge",
178+
"skills", "sessions", "usage", "config", "logs"
179+
])
180+
181+
# Register a simple reply handler
182+
@aiui.reply
183+
async def on_reply(message):
184+
return f"Unified Dashboard: {{message.content}}"
185+
186+
# Register a welcome message
187+
@aiui.welcome
188+
async def on_welcome():
189+
return "Welcome to PraisonAI Unified Dashboard! 🌟"
190+
191+
# Start aiui server
192+
if __name__ == "__main__":
193+
import uvicorn
194+
app = aiui.create_app()
195+
uvicorn.run(app, host="{host}", port={port})
196+
'''
197+
198+
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
199+
f.write(aiui_script)
200+
temp_script = f.name
201+
202+
try:
203+
console.print(f"[green]✓ Starting aiui dashboard on {host}:{port}[/green]")
204+
205+
# Check if aiui is available first
206+
result = subprocess.run([
207+
sys.executable, "-c", "import praisonaiui"
208+
], capture_output=True, text=True)
209+
210+
if result.returncode != 0:
211+
console.print("[red]Error: aiui package not installed.[/red]")
212+
console.print("[yellow]Install with: pip install aiui[/yellow]")
213+
return False
214+
215+
# Run the aiui script
216+
subprocess.run([sys.executable, temp_script])
217+
218+
finally:
219+
# Clean up temp file
220+
try:
221+
os.unlink(temp_script)
222+
except:
223+
pass
224+
225+
except ImportError:
226+
console.print("[red]Error: aiui package not installed.[/red]")
227+
console.print("[yellow]Install with: pip install aiui[/yellow]")
228+
return False
229+
except Exception as e:
230+
console.print(f"[red]Error running aiui dashboard: {e}[/red]")
231+
return False
232+
233+
return True
234+
235+
79236
def _generate_dashboard_html(host: str = "localhost") -> str:
80237
"""Generate dashboard HTML with dynamic host configuration."""
81238
dashboard_html = """<!DOCTYPE html>
@@ -393,6 +550,8 @@ def unified(
393550
ctx: typer.Context,
394551
port: int = typer.Option(3000, "--port", "-p", help="Port to run unified dashboard on"),
395552
host: str = typer.Option("127.0.0.1", "--host", help="Host to bind to (use 0.0.0.0 to expose remotely)"),
553+
auto_start: bool = typer.Option(True, "--auto-start/--no-auto-start", help="Auto-start all services"),
554+
aiui: bool = typer.Option(False, "--aiui", help="Use aiui dashboard interface (experimental)"),
396555
):
397556
"""
398557
Launch the PraisonAI Unified Dashboard.
@@ -402,22 +561,30 @@ def unified(
402561
- Claw Dashboard (Full UI) - port 8082
403562
- Clean Chat UI - port 8081
404563
405-
This unified launcher allows you to:
406-
1. Create agents visually using Flow Builder
407-
2. Chat with agents using the Chat UI
408-
3. Manage everything from Claw Dashboard
409-
4. Connect external services like Telegram
564+
This unified launcher:
565+
1. Auto-starts all services by default (like 'praisonai up')
566+
2. Creates agents visually using Flow Builder
567+
3. Chats with agents using the Chat UI
568+
4. Manages everything from Claw Dashboard
569+
5. Connects external services like Telegram
570+
6. Optionally uses aiui for enhanced dashboard experience
410571
411572
Examples:
412-
praisonai dashboard
573+
praisonai dashboard # Auto-start all services
574+
praisonai dashboard --no-auto-start # Dashboard only (no auto-start)
413575
praisonai dashboard --port 9000 --host 0.0.0.0
576+
praisonai dashboard --aiui # Use aiui interface (experimental)
414577
"""
415578
if ctx.invoked_subcommand is not None:
416579
return
417580

418581
from rich.console import Console
419582
console = Console()
420583

584+
# Check for aiui mode first
585+
if aiui:
586+
return _run_aiui_dashboard(port, host, console)
587+
421588
# Import optional dependencies inside function to avoid startup overhead
422589
try:
423590
from fastapi import FastAPI, HTTPException
@@ -429,6 +596,13 @@ def unified(
429596
console.print(f"[dim]Error details: {exc}[/dim]")
430597
raise typer.Abort()
431598

599+
# Auto-start services if enabled
600+
if auto_start:
601+
console.print("[bold green]🚀 Auto-starting PraisonAI services...[/bold green]")
602+
_auto_start_services(console, host)
603+
console.print("[green]✅ Auto-start complete[/green]")
604+
console.print()
605+
432606
# Register cleanup handlers and save originals for restoration
433607
original_handlers = _register_cleanup_handlers()
434608

@@ -554,6 +728,8 @@ async def health():
554728
console.print()
555729
console.print("[bold green]🌟 Starting PraisonAI Unified Dashboard[/bold green]")
556730
console.print(f"[dim]Unified interface on {host}:{port}[/dim]")
731+
if auto_start:
732+
console.print("[dim]Services auto-started and dashboard ready[/dim]")
557733
console.print("[dim]Access Flow Builder, Claw Dashboard, and Chat UI from one place[/dim]")
558734
console.print()
559735

0 commit comments

Comments
 (0)