123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- import json
- import os
- import re
- import shutil
- import subprocess
- import click
- import pkg_resources
- from rich.console import Console
- from embedchain.telemetry.posthog import AnonymousTelemetry
- console = Console()
- @click.group()
- def cli():
- pass
- anonymous_telemetry = AnonymousTelemetry()
- def get_pkg_path_from_name(template: str):
- try:
- # Determine the installation location of the embedchain package
- package_path = pkg_resources.resource_filename("embedchain", "")
- except ImportError:
- console.print("❌ [bold red]Failed to locate the 'embedchain' package. Is it installed?[/bold red]")
- return
- # Construct the source path from the embedchain package
- src_path = os.path.join(package_path, "deployment", template)
- if not os.path.exists(src_path):
- console.print(f"❌ [bold red]Template '{template}' not found.[/bold red]")
- return
- return src_path
- def setup_fly_io_app(extra_args):
- fly_launch_command = ["fly", "launch", "--region", "sjc", "--no-deploy"] + list(extra_args)
- try:
- console.print(f"🚀 [bold cyan]Running: {' '.join(fly_launch_command)}[/bold cyan]")
- shutil.move(".env.example", ".env")
- subprocess.run(fly_launch_command, check=True)
- console.print("✅ [bold green]'fly launch' executed successfully.[/bold green]")
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except FileNotFoundError:
- console.print(
- "❌ [bold red]'fly' command not found. Please ensure Fly CLI is installed and in your PATH.[/bold red]"
- )
- def setup_modal_com_app(extra_args):
- modal_setup_file = os.path.join(os.path.expanduser("~"), ".modal.toml")
- if os.path.exists(modal_setup_file):
- console.print(
- """✅ [bold green]Modal setup already done. You can now install the dependencies by doing \n
- `pip install -r requirements.txt`[/bold green]"""
- )
- else:
- modal_setup_cmd = ["modal", "setup"] + list(extra_args)
- console.print(f"🚀 [bold cyan]Running: {' '.join(modal_setup_cmd)}[/bold cyan]")
- subprocess.run(modal_setup_cmd, check=True)
- shutil.move(".env.example", ".env")
- console.print(
- """Great! Now you can install the dependencies by doing: \n
- `pip install -r requirements.txt`\n
- \n
- To run your app locally:\n
- `ec dev`
- """
- )
- def setup_render_com_app():
- render_setup_file = os.path.join(os.path.expanduser("~"), ".render/config.yaml")
- if os.path.exists(render_setup_file):
- console.print(
- """✅ [bold green]Render setup already done. You can now install the dependencies by doing \n
- `pip install -r requirements.txt`[/bold green]"""
- )
- else:
- render_setup_cmd = ["render", "config", "init"]
- console.print(f"🚀 [bold cyan]Running: {' '.join(render_setup_cmd)}[/bold cyan]")
- subprocess.run(render_setup_cmd, check=True)
- shutil.move(".env.example", ".env")
- console.print(
- """Great! Now you can install the dependencies by doing: \n
- `pip install -r requirements.txt`\n
- \n
- To run your app locally:\n
- `ec dev`
- """
- )
- def setup_streamlit_io_app():
- # nothing needs to be done here
- console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`")
- @cli.command()
- @click.option("--template", default="fly.io", help="The template to use.")
- @click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
- def create(template, extra_args):
- anonymous_telemetry.capture(event_name="ec_create", properties={"template_used": template})
- src_path = get_pkg_path_from_name(template)
- shutil.copytree(src_path, os.getcwd(), dirs_exist_ok=True)
- console.print(f"✅ [bold green]Successfully created app from template '{template}'.[/bold green]")
- if template == "fly.io":
- setup_fly_io_app(extra_args)
- elif template == "modal.com":
- setup_modal_com_app(extra_args)
- elif template == "render.com":
- setup_render_com_app()
- elif template == "streamlit.io":
- setup_streamlit_io_app()
- else:
- raise ValueError(f"Unknown template '{template}'.")
- embedchain_config = {"provider": template}
- with open("embedchain.json", "w") as file:
- json.dump(embedchain_config, file, indent=4)
- console.print(
- f"🎉 [green]All done! Successfully created `embedchain.json` with '{template}' as provider.[/green]"
- )
- def run_dev_fly_io(debug, host, port):
- uvicorn_command = ["uvicorn", "app:app"]
- if debug:
- uvicorn_command.append("--reload")
- uvicorn_command.extend(["--host", host, "--port", str(port)])
- try:
- console.print(f"🚀 [bold cyan]Running FastAPI app with command: {' '.join(uvicorn_command)}[/bold cyan]")
- subprocess.run(uvicorn_command, check=True)
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except KeyboardInterrupt:
- console.print("\n🛑 [bold yellow]FastAPI server stopped[/bold yellow]")
- def run_dev_modal_com():
- modal_run_cmd = ["modal", "serve", "app"]
- try:
- console.print(f"🚀 [bold cyan]Running FastAPI app with command: {' '.join(modal_run_cmd)}[/bold cyan]")
- subprocess.run(modal_run_cmd, check=True)
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except KeyboardInterrupt:
- console.print("\n🛑 [bold yellow]FastAPI server stopped[/bold yellow]")
- def run_dev_streamlit_io():
- streamlit_run_cmd = ["streamlit", "run", "app.py"]
- try:
- console.print(f"🚀 [bold cyan]Running Streamlit app with command: {' '.join(streamlit_run_cmd)}[/bold cyan]")
- subprocess.run(streamlit_run_cmd, check=True)
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except KeyboardInterrupt:
- console.print("\n🛑 [bold yellow]Streamlit server stopped[/bold yellow]")
- def run_dev_render_com(debug, host, port):
- uvicorn_command = ["uvicorn", "app:app"]
- if debug:
- uvicorn_command.append("--reload")
- uvicorn_command.extend(["--host", host, "--port", str(port)])
- try:
- console.print(f"🚀 [bold cyan]Running FastAPI app with command: {' '.join(uvicorn_command)}[/bold cyan]")
- subprocess.run(uvicorn_command, check=True)
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except KeyboardInterrupt:
- console.print("\n🛑 [bold yellow]FastAPI server stopped[/bold yellow]")
- @cli.command()
- @click.option("--debug", is_flag=True, help="Enable or disable debug mode.")
- @click.option("--host", default="127.0.0.1", help="The host address to run the FastAPI app on.")
- @click.option("--port", default=8000, help="The port to run the FastAPI app on.")
- def dev(debug, host, port):
- template = ""
- with open("embedchain.json", "r") as file:
- embedchain_config = json.load(file)
- template = embedchain_config["provider"]
- anonymous_telemetry.capture(event_name="ec_dev", properties={"template_used": template})
- if template == "fly.io":
- run_dev_fly_io(debug, host, port)
- elif template == "modal.com":
- run_dev_modal_com()
- elif template == "render.com":
- run_dev_render_com(debug, host, port)
- elif template == "streamlit.io":
- run_dev_streamlit_io()
- else:
- raise ValueError(f"Unknown template '{template}'.")
- def read_env_file(env_file_path):
- """
- Reads an environment file and returns a dictionary of key-value pairs.
- Args:
- env_file_path (str): The path to the .env file.
- Returns:
- dict: Dictionary of environment variables.
- """
- env_vars = {}
- with open(env_file_path, "r") as file:
- for line in file:
- # Ignore comments and empty lines
- if line.strip() and not line.strip().startswith("#"):
- # Assume each line is in the format KEY=VALUE
- key_value_match = re.match(r"(\w+)=(.*)", line.strip())
- if key_value_match:
- key, value = key_value_match.groups()
- env_vars[key] = value
- return env_vars
- def deploy_fly():
- app_name = ""
- with open("fly.toml", "r") as file:
- for line in file:
- if line.strip().startswith("app ="):
- app_name = line.split("=")[1].strip().strip('"')
- if not app_name:
- console.print("❌ [bold red]App name not found in fly.toml[/bold red]")
- return
- env_vars = read_env_file(".env")
- secrets_command = ["flyctl", "secrets", "set", "-a", app_name] + [f"{k}={v}" for k, v in env_vars.items()]
- deploy_command = ["fly", "deploy"]
- try:
- # Set secrets
- console.print(f"🔐 [bold cyan]Setting secrets for {app_name}[/bold cyan]")
- subprocess.run(secrets_command, check=True)
- # Deploy application
- console.print(f"🚀 [bold cyan]Running: {' '.join(deploy_command)}[/bold cyan]")
- subprocess.run(deploy_command, check=True)
- console.print("✅ [bold green]'fly deploy' executed successfully.[/bold green]")
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except FileNotFoundError:
- console.print(
- "❌ [bold red]'fly' command not found. Please ensure Fly CLI is installed and in your PATH.[/bold red]"
- )
- def deploy_modal():
- modal_deploy_cmd = ["modal", "deploy", "app"]
- try:
- console.print(f"🚀 [bold cyan]Running: {' '.join(modal_deploy_cmd)}[/bold cyan]")
- subprocess.run(modal_deploy_cmd, check=True)
- console.print("✅ [bold green]'modal deploy' executed successfully.[/bold green]")
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except FileNotFoundError:
- console.print(
- "❌ [bold red]'modal' command not found. Please ensure Modal CLI is installed and in your PATH.[/bold red]"
- )
- def deploy_streamlit():
- streamlit_deploy_cmd = ["streamlit", "run", "app.py"]
- try:
- console.print(f"🚀 [bold cyan]Running: {' '.join(streamlit_deploy_cmd)}[/bold cyan]")
- console.print(
- """\n\n✅ [bold yellow]To deploy a streamlit app, you can directly it from the UI.\n
- Click on the 'Deploy' button on the top right corner of the app.\n
- For more information, please refer to https://docs.embedchain.ai/deployment/streamlit_io
- [/bold yellow]
- \n\n"""
- )
- subprocess.run(streamlit_deploy_cmd, check=True)
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except FileNotFoundError:
- console.print(
- """❌ [bold red]'streamlit' command not found.\n
- Please ensure Streamlit CLI is installed and in your PATH.[/bold red]"""
- )
- def deploy_render():
- render_deploy_cmd = ["render", "blueprint", "launch"]
- try:
- console.print(f"🚀 [bold cyan]Running: {' '.join(render_deploy_cmd)}[/bold cyan]")
- subprocess.run(render_deploy_cmd, check=True)
- console.print("✅ [bold green]'render blueprint launch' executed successfully.[/bold green]")
- except subprocess.CalledProcessError as e:
- console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
- except FileNotFoundError:
- console.print(
- "❌ [bold red]'render' command not found. Please ensure Render CLI is installed and in your PATH.[/bold red]"
- )
- @cli.command()
- def deploy():
- # Check for platform-specific files
- template = ""
- with open("embedchain.json", "r") as file:
- embedchain_config = json.load(file)
- template = embedchain_config["provider"]
- anonymous_telemetry.capture(event_name="ec_deploy", properties={"template_used": template})
- if template == "fly.io":
- deploy_fly()
- elif template == "modal.com":
- deploy_modal()
- elif template == "render.com":
- deploy_render()
- elif template == "streamlit.io":
- deploy_streamlit()
- else:
- console.print("❌ [bold red]No recognized deployment platform found.[/bold red]")
|