#!/usr/bin/env python3 """ Environment Setup for NotebookLM Skill Manages virtual environment and dependencies automatically """ import os import sys import subprocess import venv from pathlib import Path class SkillEnvironment: """Manages skill-specific virtual environment""" def __init__(self): # Skill directory paths self.skill_dir = Path(__file__).parent.parent self.venv_dir = self.skill_dir / ".venv" self.requirements_file = self.skill_dir / "requirements.txt" # Python executable in venv if os.name == 'nt': # Windows self.venv_python = self.venv_dir / "Scripts" / "python.exe" self.venv_pip = self.venv_dir / "Scripts" / "pip.exe" else: # Unix/Linux/Mac self.venv_python = self.venv_dir / "bin" / "python" self.venv_pip = self.venv_dir / "bin" / "pip" def ensure_venv(self) -> bool: """Ensure virtual environment exists and is set up""" # Check if we're already in the correct venv if self.is_in_skill_venv(): print("āœ… Already running in skill virtual environment") return True # Create venv if it doesn't exist if not self.venv_dir.exists(): print(f"šŸ”§ Creating virtual environment in {self.venv_dir.name}/") try: venv.create(self.venv_dir, with_pip=True) print("āœ… Virtual environment created") except Exception as e: print(f"āŒ Failed to create venv: {e}") return False # Install/update dependencies if self.requirements_file.exists(): print("šŸ“¦ Installing dependencies...") try: # Upgrade pip first subprocess.run( [str(self.venv_pip), "install", "--upgrade", "pip"], check=True, capture_output=True, text=True ) # Install requirements result = subprocess.run( [str(self.venv_pip), "install", "-r", str(self.requirements_file)], check=True, capture_output=True, text=True ) print("āœ… Dependencies installed") # Install Chrome for Patchright (not Chromium!) # Using real Chrome ensures cross-platform reliability and consistent browser fingerprinting # See: https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python#anti-detection print("🌐 Installing Google Chrome for Patchright...") try: subprocess.run( [str(self.venv_python), "-m", "patchright", "install", "chrome"], check=True, capture_output=True, text=True ) print("āœ… Chrome installed") except subprocess.CalledProcessError as e: print(f"āš ļø Warning: Failed to install Chrome: {e}") print(" You may need to run manually: python -m patchright install chrome") print(" Chrome is required (not Chromium) for reliability!") return True except subprocess.CalledProcessError as e: print(f"āŒ Failed to install dependencies: {e}") print(f" Output: {e.output if hasattr(e, 'output') else 'No output'}") return False else: print("āš ļø No requirements.txt found, skipping dependency installation") return True def is_in_skill_venv(self) -> bool: """Check if we're already running in the skill's venv""" if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): # We're in a venv, check if it's ours venv_path = Path(sys.prefix) return venv_path == self.venv_dir return False def get_python_executable(self) -> str: """Get the correct Python executable to use""" if self.venv_python.exists(): return str(self.venv_python) return sys.executable def run_script(self, script_name: str, args: list = None) -> int: """Run a script with the virtual environment""" script_path = self.skill_dir / "scripts" / script_name if not script_path.exists(): print(f"āŒ Script not found: {script_path}") return 1 # Ensure venv is set up if not self.ensure_venv(): print("āŒ Failed to set up environment") return 1 # Build command cmd = [str(self.venv_python), str(script_path)] if args: cmd.extend(args) print(f"šŸš€ Running: {script_name} with venv Python") try: # Run the script with venv Python result = subprocess.run(cmd) return result.returncode except Exception as e: print(f"āŒ Failed to run script: {e}") return 1 def activate_instructions(self) -> str: """Get instructions for manual activation""" if os.name == 'nt': activate = self.venv_dir / "Scripts" / "activate.bat" return f"Run: {activate}" else: activate = self.venv_dir / "bin" / "activate" return f"Run: source {activate}" def main(): """Main entry point for environment setup""" import argparse parser = argparse.ArgumentParser( description='Setup NotebookLM skill environment' ) parser.add_argument( '--check', action='store_true', help='Check if environment is set up' ) parser.add_argument( '--run', help='Run a script with the venv (e.g., --run ask_question.py)' ) parser.add_argument( 'args', nargs='*', help='Arguments to pass to the script' ) args = parser.parse_args() env = SkillEnvironment() if args.check: if env.venv_dir.exists(): print(f"āœ… Virtual environment exists: {env.venv_dir}") print(f" Python: {env.get_python_executable()}") print(f" To activate manually: {env.activate_instructions()}") else: print(f"āŒ No virtual environment found") print(f" Run setup_environment.py to create it") return if args.run: # Run a script with venv return env.run_script(args.run, args.args) # Default: ensure environment is set up if env.ensure_venv(): print("\nāœ… Environment ready!") print(f" Virtual env: {env.venv_dir}") print(f" Python: {env.get_python_executable()}") print(f"\nTo activate manually: {env.activate_instructions()}") print(f"Or run scripts directly: python setup_environment.py --run script_name.py") else: print("\nāŒ Environment setup failed") return 1 if __name__ == "__main__": sys.exit(main() or 0)