@@ -457,6 +457,301 @@ def evals(
457457 raise typer .Exit (1 )
458458
459459
460+ @app .command ()
461+ def quickstart (
462+ template : Optional [str ] = typer .Argument (
463+ None ,
464+ help = "Template name (e.g., 'rag_eval', 'agent_evals'). Leave empty to see available templates." ,
465+ ),
466+ output_dir : str = typer .Option (
467+ "." , "--output-dir" , "-o" , help = "Directory to create the project in"
468+ ),
469+ ):
470+ """
471+ Clone a complete example project to get started with Ragas.
472+
473+ Similar to 'uvx hud-python quickstart', this creates a complete example
474+ project with all necessary files and dependencies.
475+
476+ Examples:
477+ ragas quickstart # List available templates
478+ ragas quickstart rag_eval # Create a RAG evaluation project
479+ ragas quickstart agent_evals -o ./my-project
480+ """
481+ import shutil
482+ import time
483+ from pathlib import Path
484+
485+ # Define available templates with descriptions
486+ templates = {
487+ "rag_eval" : {
488+ "name" : "RAG Evaluation" ,
489+ "description" : "Evaluate a RAG (Retrieval Augmented Generation) system with custom metrics" ,
490+ "source_path" : "ragas_examples/rag_eval" ,
491+ },
492+ "agent_evals" : {
493+ "name" : "Agent Evaluation" ,
494+ "description" : "Evaluate AI agents with structured metrics and workflows" ,
495+ "source_path" : "ragas_examples/agent_evals" ,
496+ },
497+ "benchmark_llm" : {
498+ "name" : "LLM Benchmarking" ,
499+ "description" : "Benchmark and compare different LLM models with datasets" ,
500+ "source_path" : "ragas_examples/benchmark_llm" ,
501+ },
502+ "prompt_evals" : {
503+ "name" : "Prompt Evaluation" ,
504+ "description" : "Evaluate and compare different prompt variations" ,
505+ "source_path" : "ragas_examples/prompt_evals" ,
506+ },
507+ "workflow_eval" : {
508+ "name" : "Workflow Evaluation" ,
509+ "description" : "Evaluate complex LLM workflows and pipelines" ,
510+ "source_path" : "ragas_examples/workflow_eval" ,
511+ },
512+ }
513+
514+ # If no template specified, list available templates
515+ if template is None :
516+ console .print (
517+ "\n [bold cyan]Available Ragas Quickstart Templates:[/bold cyan]\n "
518+ )
519+
520+ # Create a table of templates
521+ table = Table (show_header = True , header_style = "bold yellow" )
522+ table .add_column ("Template" , style = "cyan" , no_wrap = True )
523+ table .add_column ("Name" , style = "green" )
524+ table .add_column ("Description" , style = "white" )
525+
526+ for template_id , template_info in templates .items ():
527+ table .add_row (
528+ template_id , template_info ["name" ], template_info ["description" ]
529+ )
530+
531+ console .print (table )
532+ console .print ("\n [bold]Usage:[/bold]" )
533+ console .print (" ragas quickstart [template_name]" )
534+ console .print ("\n [bold]Example:[/bold]" )
535+ console .print (" ragas quickstart rag_eval" )
536+ console .print (" ragas quickstart agent_evals --output-dir ./my-project\n " )
537+ return
538+
539+ # Validate template name
540+ if template not in templates :
541+ error (f"Unknown template: { template } " )
542+ console .print (f"\n Available templates: { ', ' .join (templates .keys ())} " )
543+ console .print ("Run 'ragas quickstart' to see all available templates." )
544+ raise typer .Exit (1 )
545+
546+ template_info = templates [template ]
547+ template_path = template_info ["source_path" ].replace ("ragas_examples/" , "" )
548+
549+ # Try to find examples locally first (for development and testing)
550+ # Look for examples in the installed ragas-examples package or local dev environment
551+ source_path = None
552+ temp_dir = None
553+
554+ try :
555+ import ragas_examples
556+
557+ if ragas_examples .__file__ is not None :
558+ examples_root = Path (ragas_examples .__file__ ).parent
559+ local_source = examples_root / template_path
560+ if local_source .exists ():
561+ source_path = local_source
562+ info ("Using locally installed examples" )
563+ except ImportError :
564+ pass
565+
566+ # If not found locally, check if we're in the ragas repository (dev mode)
567+ if source_path is None :
568+ # Try to find examples directory relative to this file (development mode)
569+ cli_file = Path (__file__ ).resolve ()
570+ repo_root = cli_file .parent .parent .parent # Go up from src/ragas/cli.py
571+ local_examples = repo_root / "examples" / "ragas_examples" / template_path
572+ if local_examples .exists ():
573+ source_path = local_examples
574+ info ("Using local development examples" )
575+
576+ # If still not found, download from GitHub
577+ if source_path is None :
578+ import tempfile
579+ import urllib .request
580+ import zipfile
581+
582+ github_repo = "explodinggradients/ragas"
583+ branch = "main"
584+
585+ # Create temporary directory for download
586+ temp_dir = Path (tempfile .mkdtemp ())
587+
588+ try :
589+ # Download the specific template folder from GitHub
590+ archive_url = (
591+ f"https://github.com/{ github_repo } /archive/refs/heads/{ branch } .zip"
592+ )
593+
594+ with Live (
595+ Spinner (
596+ "dots" , text = "Downloading template from GitHub..." , style = "cyan"
597+ ),
598+ console = console ,
599+ ):
600+ zip_path = temp_dir / "repo.zip"
601+ urllib .request .urlretrieve (archive_url , zip_path )
602+
603+ with zipfile .ZipFile (zip_path , "r" ) as zip_ref :
604+ zip_ref .extractall (temp_dir )
605+
606+ extracted_folders = [
607+ f
608+ for f in temp_dir .iterdir ()
609+ if f .is_dir () and f .name .startswith ("ragas-" )
610+ ]
611+ if not extracted_folders :
612+ error ("Failed to extract template from GitHub archive" )
613+ raise typer .Exit (1 )
614+
615+ repo_dir = extracted_folders [0 ]
616+ source_path = repo_dir / "examples" / "ragas_examples" / template_path
617+
618+ if not source_path .exists ():
619+ error (f"Template not found in repository: { template_path } " )
620+ console .print (f"Looking for: { source_path } " )
621+ raise typer .Exit (1 )
622+
623+ except Exception as e :
624+ error (f"Failed to download template from GitHub: { e } " )
625+ console .print ("\n You can also manually clone the repository:" )
626+ console .print (f" git clone https://github.com/{ github_repo } .git" )
627+ console .print (
628+ f" cp -r ragas/examples/ragas_examples/{ template_path } ./{ template } "
629+ )
630+ raise typer .Exit (1 )
631+
632+ # Determine output directory
633+ output_path = Path (output_dir ) / template
634+
635+ if output_path .exists ():
636+ warning (f"Directory already exists: { output_path } " )
637+ overwrite = typer .confirm ("Do you want to overwrite it?" , default = False )
638+ if not overwrite :
639+ info ("Operation cancelled." )
640+ raise typer .Exit (0 )
641+ shutil .rmtree (output_path )
642+
643+ # Copy the template
644+ with Live (
645+ Spinner (
646+ "dots" , text = f"Creating { template_info ['name' ]} project..." , style = "green"
647+ ),
648+ console = console ,
649+ ) as live :
650+ live .update (Spinner ("dots" , text = "Copying template files..." , style = "green" ))
651+ shutil .copytree (source_path , output_path )
652+ time .sleep (0.3 )
653+
654+ live .update (
655+ Spinner ("dots" , text = "Setting up project structure..." , style = "green" )
656+ )
657+
658+ evals_dir = output_path / "evals"
659+ evals_dir .mkdir (exist_ok = True )
660+ (evals_dir / "datasets" ).mkdir (exist_ok = True )
661+ (evals_dir / "experiments" ).mkdir (exist_ok = True )
662+ (evals_dir / "logs" ).mkdir (exist_ok = True )
663+ time .sleep (0.2 )
664+
665+ # Create a README.md with setup instructions
666+ live .update (Spinner ("dots" , text = "Creating documentation..." , style = "green" ))
667+ readme_content = f"""# { template_info ["name" ]}
668+
669+ { template_info ["description" ]}
670+
671+ ## Setup
672+
673+ 1. Set your OpenAI API key (or other LLM provider):
674+ ```bash
675+ export OPENAI_API_KEY="your-api-key"
676+ ```
677+
678+ 2. Install dependencies:
679+ ```bash
680+ pip install ragas openai
681+ ```
682+
683+ ## Running the Example
684+
685+ Run the evaluation:
686+ ```bash
687+ python app.py
688+ ```
689+
690+ Or run via the CLI:
691+ ```bash
692+ ragas evals evals/evals.py --dataset test_data --metrics [metric_names]
693+ ```
694+
695+ ## Project Structure
696+
697+ ```
698+ { template } /
699+ ├── app.py # Your application code (RAG system, agent, etc.)
700+ ├── evals/ # Evaluation-related code and data
701+ │ ├── evals.py # Evaluation metrics and experiment definitions
702+ │ ├── datasets/ # Test datasets
703+ │ ├── experiments/ # Experiment results
704+ │ └── logs/ # Evaluation logs and traces
705+ └── README.md
706+ ```
707+
708+ This structure separates your application code from evaluation code, making it easy to:
709+ - Develop and test your application independently
710+ - Run evaluations without mixing concerns
711+ - Track evaluation results separately from application logic
712+
713+ ## Next Steps
714+
715+ 1. Implement your application logic in `app.py`
716+ 2. Review and modify the metrics in `evals/evals.py`
717+ 3. Customize the dataset in `evals/datasets/`
718+ 4. Run experiments and analyze results
719+ 5. Iterate on your prompts and system design
720+
721+ ## Documentation
722+
723+ Visit https://docs.ragas.io for more information.
724+ """
725+
726+ readme_path = output_path / "README.md"
727+ with open (readme_path , "w" , encoding = "utf-8" ) as f :
728+ f .write (readme_content )
729+ time .sleep (0.2 )
730+
731+ live .update (Spinner ("dots" , text = "Finalizing project..." , style = "green" ))
732+ time .sleep (0.3 )
733+
734+ # Cleanup temporary directory if we downloaded from GitHub
735+ if temp_dir is not None :
736+ try :
737+ shutil .rmtree (temp_dir )
738+ except Exception :
739+ pass
740+
741+ # Success message with next steps
742+ success (f"\n ✓ Created { template_info ['name' ]} project at: { output_path } " )
743+ console .print ("\n [bold cyan]Next Steps:[/bold cyan]" )
744+ console .print (f" 1. cd { output_path } " )
745+ console .print (" 2. export OPENAI_API_KEY='your-api-key'" )
746+ console .print (" 3. pip install ragas openai" )
747+ console .print (" 4. python app.py" )
748+ console .print ("\n [bold]Project Structure:[/bold]" )
749+ console .print (" app.py - Your application code" )
750+ console .print (" evals/ - All evaluation-related code and data" )
751+ console .print ("\n [bold]Quick Start:[/bold]" )
752+ console .print (f" cd { output_path } && python app.py\n " )
753+
754+
460755@app .command ()
461756def hello_world (
462757 directory : str = typer .Argument (
@@ -610,7 +905,7 @@ async def run_experiment(row: TestDataRow):
610905'''
611906
612907 evals_path = os .path .join (directory , "hello_world" , "evals.py" )
613- with open (evals_path , "w" ) as f :
908+ with open (evals_path , "w" , encoding = "utf-8" ) as f :
614909 f .write (evals_content )
615910 time .sleep (0.5 ) # Brief pause to show spinner
616911
0 commit comments