diff --git a/docs/get-started/full-stack.mdx b/docs/get-started/full-stack.mdx index 1ecd0cb8..838fabb9 100644 --- a/docs/get-started/full-stack.mdx +++ b/docs/get-started/full-stack.mdx @@ -14,17 +14,19 @@ Make sure that you have installed the following: For the purpose of the demo, you have to set `OPENAI_API_KEY` to start with but you can choose any llm by changing the configuration easily. -Now run the following command: +Now run the following commands: ```bash -ec runserver +ec create-app my-app +cd my-app +ec start ``` Once you run this command, Embedchain does the following: 1. Fetch full stack template that uses FastAPI for backend, and Next.JS template for frontend 2. Install necessary requirements -3. Launch the frontend and backend server for you to interact with. +3. Launch the frontend and backend server for you to interact with Once you are done, visit `http://localhost:3000` and you will see a chat UI as shown below. diff --git a/embedchain/cli.py b/embedchain/cli.py index e6cca4c1..8414a22d 100644 --- a/embedchain/cli.py +++ b/embedchain/cli.py @@ -1,35 +1,33 @@ import json import os -import re import shutil import signal import subprocess import sys import tempfile +import time import zipfile from pathlib import Path import click -import pkg_resources import requests from rich.console import Console from embedchain.telemetry.posthog import AnonymousTelemetry +from embedchain.utils.cli import (deploy_fly, deploy_gradio_app, + deploy_hf_spaces, deploy_modal, + deploy_render, deploy_streamlit, + get_pkg_path_from_name, setup_fly_io_app, + setup_gradio_app, setup_hf_app, + setup_modal_com_app, setup_render_com_app, + setup_streamlit_io_app) console = Console() - - -@click.group() -def cli(): - pass - - -anonymous_telemetry = AnonymousTelemetry() - - api_process = None ui_process = None +anonymous_telemetry = AnonymousTelemetry() + def signal_handler(sig, frame): """Signal handler to catch termination signals and kill server processes.""" @@ -44,110 +42,126 @@ def signal_handler(sig, frame): sys.exit(0) -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]") +@click.group() +def cli(): + pass + + +@cli.command() +@click.argument("app_name") +@click.pass_context +def create_app(ctx, app_name): + if Path(app_name).exists(): + console.print( + f"❌ [red]Directory '{app_name}' already exists. Try using a new directory name, or remove it.[/red]" + ) return - # Construct the source path from the embedchain package - src_path = os.path.join(package_path, "deployment", template) + os.makedirs(app_name) + os.chdir(app_name) - if not os.path.exists(src_path): - console.print(f"❌ [bold red]Template '{template}' not found.[/bold red]") + # Step 1: Download the zip file + zip_url = "http://github.com/embedchain/ec-admin/archive/main.zip" + console.print(f"Creating a new embedchain app in [green]{Path().resolve()}[/green]\n") + try: + response = requests.get(zip_url) + response.raise_for_status() + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + tmp_file.write(response.content) + zip_file_path = tmp_file.name + console.print("✅ [bold green]Fetched template successfully.[/bold green]") + except requests.RequestException as e: + console.print(f"❌ [bold red]Failed to download zip file: {e}[/bold red]") + anonymous_telemetry.capture(event_name="ec_create_app", properties={"success": False}) return - return src_path - - -def setup_fly_io_app(extra_args): - fly_launch_command = ["fly", "launch", "--region", "sjc", "--no-deploy"] + list(extra_args) + # Step 2: Extract the zip file 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]" - ) + with zipfile.ZipFile(zip_file_path, "r") as zip_ref: + # Get the name of the root directory inside the zip file + root_dir = Path(zip_ref.namelist()[0]) + for member in zip_ref.infolist(): + # Build the path to extract the file to, skipping the root directory + target_file = Path(member.filename).relative_to(root_dir) + source_file = zip_ref.open(member, "r") + if member.is_dir(): + # Create directory if it doesn't exist + os.makedirs(target_file, exist_ok=True) + else: + with open(target_file, "wb") as file: + # Write the file + shutil.copyfileobj(source_file, file) + console.print("✅ [bold green]Extracted zip file successfully.[/bold green]") + anonymous_telemetry.capture(event_name="ec_create_app", properties={"success": True}) + except zipfile.BadZipFile: + console.print("❌ [bold red]Error in extracting zip file. The file might be corrupted.[/bold red]") + anonymous_telemetry.capture(event_name="ec_create_app", properties={"success": False}) + return + + ctx.invoke(install_reqs) -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` - """ - ) +@cli.command() +def install_reqs(): + try: + console.print("Installing python requirements...\n") + time.sleep(2) + os.chdir("api") + subprocess.run(["pip", "install", "-r", "requirements.txt"], check=True) + os.chdir("..") + console.print("\n ✅ [bold green]Installed API requirements successfully.[/bold green]\n") + except Exception as e: + console.print(f"❌ [bold red]Failed to install API requirements: {e}[/bold red]") + anonymous_telemetry.capture(event_name="ec_install_reqs", properties={"success": False}) + return + + try: + os.chdir("ui") + subprocess.run(["yarn"], check=True) + console.print("\n✅ [bold green]Successfully installed frontend requirements.[/bold green]") + anonymous_telemetry.capture(event_name="ec_install_reqs", properties={"success": True}) + except Exception as e: + console.print(f"❌ [bold red]Failed to install frontend requirements. Error: {e}[/bold red]") + anonymous_telemetry.capture(event_name="ec_install_reqs", properties={"success": False}) -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` - """ - ) +@cli.command() +def start(): + # Set up signal handling + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + # Step 1: Start the API server + try: + os.chdir("api") + api_process = subprocess.Popen(["python", "-m", "main"], stdout=None, stderr=None) + os.chdir("..") + console.print("✅ [bold green]API server started successfully.[/bold green]") + except Exception as e: + console.print(f"❌ [bold red]Failed to start the API server: {e}[/bold red]") + anonymous_telemetry.capture(event_name="ec_start", properties={"success": False}) + return -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`") + # Sleep for 2 seconds to give the user time to read the message + time.sleep(2) + # Step 2: Install UI requirements and start the UI server + try: + os.chdir("ui") + subprocess.run(["yarn"], check=True) + ui_process = subprocess.Popen(["yarn", "dev"]) + console.print("✅ [bold green]UI server started successfully.[/bold green]") + anonymous_telemetry.capture(event_name="ec_start", properties={"success": True}) + except Exception as e: + console.print(f"❌ [bold red]Failed to start the UI server: {e}[/bold red]") + anonymous_telemetry.capture(event_name="ec_start", properties={"success": False}) -def setup_gradio_app(): - # nothing needs to be done here - console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`") - - -def setup_hf_app(): - subprocess.run(["pip", "install", "huggingface_hub[cli]"], check=True) - hf_setup_file = os.path.join(os.path.expanduser("~"), ".cache/huggingface/token") - if os.path.exists(hf_setup_file): - console.print( - """✅ [bold green]HuggingFace setup already done. You can now install the dependencies by doing \n - `pip install -r requirements.txt`[/bold green]""" - ) - else: - console.print( - """🚀 [cyan]Running: huggingface-cli login \n - Please provide a [bold]WRITE[/bold] token so that we can directly deploy\n - your apps from the terminal.[/cyan] - """ - ) - subprocess.run(["huggingface-cli", "login"], check=True) - console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`") + # Keep the script running until it receives a kill signal + try: + api_process.wait() + ui_process.wait() + except KeyboardInterrupt: + console.print("\n🛑 [bold yellow]Stopping server...[/bold yellow]") @cli.command() @@ -277,141 +291,6 @@ def dev(debug, host, port): 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]" # noqa:E501 - ) - - -def deploy_gradio_app(): - gradio_deploy_cmd = ["gradio", "deploy"] - - try: - console.print(f"🚀 [bold cyan]Running: {' '.join(gradio_deploy_cmd)}[/bold cyan]") - subprocess.run(gradio_deploy_cmd, check=True) - console.print("✅ [bold green]'gradio 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]'gradio' command not found. Please ensure Gradio CLI is installed and in your PATH.[/bold red]" # noqa:E501 - ) - - -def deploy_hf_spaces(ec_app_name): - if not ec_app_name: - console.print("❌ [bold red]'name' not found in embedchain.json[/bold red]") - return - hf_spaces_deploy_cmd = ["huggingface-cli", "upload", ec_app_name, ".", ".", "--repo-type=space"] - - try: - console.print(f"🚀 [bold cyan]Running: {' '.join(hf_spaces_deploy_cmd)}[/bold cyan]") - subprocess.run(hf_spaces_deploy_cmd, check=True) - console.print("✅ [bold green]'huggingface-cli upload' executed successfully.[/bold green]") - except subprocess.CalledProcessError as e: - console.print(f"❌ [bold red]An error occurred: {e}[/bold red]") - - @cli.command() def deploy(): # Check for platform-specific files @@ -437,86 +316,3 @@ def deploy(): deploy_hf_spaces(ec_app_name) else: console.print("❌ [bold red]No recognized deployment platform found.[/bold red]") - - -@cli.command() -def runserver(): - # Set up signal handling - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - # Check if 'api' and 'ui' directories exist - if os.path.exists("api") and os.path.exists("ui"): - pass - else: - # Step 1: Download the zip file - zip_url = "http://github.com/embedchain/ec-admin/archive/main.zip" - try: - response = requests.get(zip_url) - response.raise_for_status() - with tempfile.NamedTemporaryFile(delete=False) as tmp_file: - tmp_file.write(response.content) - zip_file_path = tmp_file.name - console.print("✅ [bold green]Downloaded zip file successfully.[/bold green]") - except requests.RequestException as e: - console.print(f"❌ [bold red]Failed to download zip file: {e}[/bold red]") - return - - # Step 2: Extract the zip file - try: - with zipfile.ZipFile(zip_file_path, "r") as zip_ref: - # Get the name of the root directory inside the zip file - root_dir = Path(zip_ref.namelist()[0]) - for member in zip_ref.infolist(): - # Build the path to extract the file to, skipping the root directory - target_file = Path(member.filename).relative_to(root_dir) - source_file = zip_ref.open(member, "r") - if member.is_dir(): - # Create directory if it doesn't exist - os.makedirs(target_file, exist_ok=True) - else: - with open(target_file, "wb") as file: - # Write the file - shutil.copyfileobj(source_file, file) - console.print("✅ [bold green]Extracted zip file successfully.[/bold green]") - except zipfile.BadZipFile: - console.print("❌ [bold red]Error in extracting zip file. The file might be corrupted.[/bold red]") - return - - # Step 3: Install API requirements - try: - os.chdir("api") - subprocess.run(["pip", "install", "-r", "requirements.txt"], check=True) - os.chdir("..") - console.print("✅ [bold green]Installed API requirements successfully.[/bold green]") - except Exception as e: - console.print(f"❌ [bold red]Failed to install API requirements: {e}[/bold red]") - return - - # Step 4: Start the API server - try: - os.chdir("api") - api_process = subprocess.Popen( - ["uvicorn", "main:app", "--reload", "--host", "127.0.0.1", "--port", "8000"], stdout=None, stderr=None - ) - os.chdir("..") - console.print("✅ [bold green]API server started successfully.[/bold green]") - except Exception as e: - console.print(f"❌ [bold red]Failed to start the API server: {e}[/bold red]") - return - - # Step 5: Install UI requirements and start the UI server - try: - os.chdir("ui") - subprocess.run(["yarn"], check=True) - subprocess.Popen(["yarn", "dev"]) - console.print("✅ [bold green]UI server started successfully.[/bold green]") - except Exception as e: - console.print(f"❌ [bold red]Failed to start the UI server: {e}[/bold red]") - - # Keep the script running until it receives a kill signal - try: - api_process.wait() - ui_process.wait() - except KeyboardInterrupt: - console.print("\n🛑 [bold yellow]Stopping server...[/bold yellow]") diff --git a/embedchain/utils/cli.py b/embedchain/utils/cli.py new file mode 100644 index 00000000..bc2cf9f0 --- /dev/null +++ b/embedchain/utils/cli.py @@ -0,0 +1,317 @@ +import os +import re +import shutil +import subprocess + +import pkg_resources +from rich.console import Console + +console = Console() + + +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`") + + +def setup_gradio_app(): + # nothing needs to be done here + console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`") + + +def setup_hf_app(): + subprocess.run(["pip", "install", "huggingface_hub[cli]"], check=True) + hf_setup_file = os.path.join(os.path.expanduser("~"), ".cache/huggingface/token") + if os.path.exists(hf_setup_file): + console.print( + """✅ [bold green]HuggingFace setup already done. You can now install the dependencies by doing \n + `pip install -r requirements.txt`[/bold green]""" + ) + else: + console.print( + """🚀 [cyan]Running: huggingface-cli login \n + Please provide a [bold]WRITE[/bold] token so that we can directly deploy\n + your apps from the terminal.[/cyan] + """ + ) + subprocess.run(["huggingface-cli", "login"], check=True) + console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`") + + +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]") + + +def run_dev_gradio(): + gradio_run_cmd = ["gradio", "app.py"] + try: + console.print(f"🚀 [bold cyan]Running Gradio app with command: {' '.join(gradio_run_cmd)}[/bold cyan]") + subprocess.run(gradio_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]Gradio server stopped[/bold yellow]") + + +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]" # noqa:E501 + ) + + +def deploy_gradio_app(): + gradio_deploy_cmd = ["gradio", "deploy"] + + try: + console.print(f"🚀 [bold cyan]Running: {' '.join(gradio_deploy_cmd)}[/bold cyan]") + subprocess.run(gradio_deploy_cmd, check=True) + console.print("✅ [bold green]'gradio 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]'gradio' command not found. Please ensure Gradio CLI is installed and in your PATH.[/bold red]" # noqa:E501 + ) + + +def deploy_hf_spaces(ec_app_name): + if not ec_app_name: + console.print("❌ [bold red]'name' not found in embedchain.json[/bold red]") + return + hf_spaces_deploy_cmd = ["huggingface-cli", "upload", ec_app_name, ".", ".", "--repo-type=space"] + + try: + console.print(f"🚀 [bold cyan]Running: {' '.join(hf_spaces_deploy_cmd)}[/bold cyan]") + subprocess.run(hf_spaces_deploy_cmd, check=True) + console.print("✅ [bold green]'huggingface-cli upload' executed successfully.[/bold green]") + except subprocess.CalledProcessError as e: + console.print(f"❌ [bold red]An error occurred: {e}[/bold red]") diff --git a/pyproject.toml b/pyproject.toml index 34021617..289264ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "embedchain" -version = "0.1.53" +version = "0.1.54" description = "Data platform for LLMs - Load, index, retrieve and sync any unstructured data" authors = [ "Taranjeet Singh ",