@@ -342,6 +342,88 @@ def cypher_helper_visual(query: str):
342342 db_manager .close_driver ()
343343
344344
345+ import uvicorn
346+ import urllib .parse
347+ from ..viz .server import run_server , set_db_manager
348+
349+ def visualize_helper (repo_path : Optional [str ] = None , port : int = 8000 ):
350+ """"Generates an interactive visualization using the Playground UI."""
351+ services = _initialize_services ()
352+ if not all (services ):
353+ return
354+
355+ db_manager , _ , _ = services
356+
357+ # Set the DB manager for the server
358+ set_db_manager (db_manager )
359+
360+ # Determine the static directory (built React app)
361+ # This points to src/codegraphcontext/viz/dist where we build the website
362+ # (relative to src/codegraphcontext/cli/cli_helpers.py)
363+ # Using .resolve() is more robust for path comparison and existence checks
364+ this_file = Path (__file__ ).resolve ()
365+ package_root = this_file .parent .parent
366+ static_dir = package_root / "viz" / "dist"
367+
368+ # Fallback for development if not yet built in viz/dist
369+ if not static_dir .exists ():
370+ # Look for website/dist in the project root (3 levels up from cli/cli_helpers.py, 4 parents)
371+ # 1: cli/, 2: codegraphcontext/, 3: src/, 4: project_root/
372+ project_root = this_file .parent .parent .parent .parent
373+ dev_static_dir = project_root / "website" / "dist"
374+
375+ # Also try one level up from package_root just in case of different layouts
376+ alt_dev_dir = package_root .parent .parent / "website" / "dist"
377+
378+ if dev_static_dir .exists ():
379+ static_dir = dev_static_dir
380+ elif alt_dev_dir .exists ():
381+ static_dir = alt_dev_dir
382+ else :
383+ # Last resort: try current working directory
384+ cwd_static_dir = Path .cwd () / "website" / "dist"
385+ if cwd_static_dir .exists ():
386+ static_dir = cwd_static_dir
387+ else :
388+ console .print (f"[yellow]Warning: Visualization assets not found.[/yellow]" )
389+ console .print (f"[dim]Checked paths:[/dim]" )
390+ console .print (f" [dim]- { static_dir } [/dim]" )
391+ console .print (f" [dim]- { dev_static_dir } [/dim]" )
392+ console .print (f" [dim]- { alt_dev_dir } [/dim]" )
393+ console .print (f" [dim]- { cwd_static_dir } [/dim]" )
394+ console .print ("[dim]Please run 'cd website && npm run build' first.[/dim]" )
395+ # We continue anyway to let the server start (helpful for dev)
396+
397+ # Construct the URL
398+ backend_url = f"http://localhost:{ port } "
399+ params = {"backend" : backend_url }
400+ if repo_path :
401+ params ["repo_path" ] = str (Path (repo_path ).resolve ())
402+
403+ query_string = urllib .parse .urlencode (params )
404+ visualization_url = f"{ backend_url } /explore?{ query_string } "
405+
406+ console .print (f"[green]Starting visualizer server on { backend_url } ...[/green]" )
407+ console .print (f"[cyan]Opening Playground UI:[/cyan] { visualization_url } " )
408+
409+ # Open browser in a separate thread/process if possible, or just before starting server
410+ def open_browser ():
411+ import time
412+ import webbrowser
413+ time .sleep (1.5 ) # Give the server a moment to start
414+ webbrowser .open (visualization_url )
415+
416+ import threading
417+ threading .Thread (target = open_browser , daemon = True ).start ()
418+
419+ try :
420+ run_server (host = "127.0.0.1" , port = port , static_dir = str (static_dir ))
421+ except Exception as e :
422+ console .print (f"[bold red]An error occurred while running the server:[/bold red] { e } " )
423+ finally :
424+ db_manager .close_driver ()
425+
426+
345427def reindex_helper (path : str ):
346428 """Force re-index by deleting and rebuilding the repository."""
347429 time_start = time .time ()
0 commit comments