cli.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import os
  2. import re
  3. import shutil
  4. import subprocess
  5. import pkg_resources
  6. from rich.console import Console
  7. console = Console()
  8. def get_pkg_path_from_name(template: str):
  9. try:
  10. # Determine the installation location of the embedchain package
  11. package_path = pkg_resources.resource_filename("embedchain", "")
  12. except ImportError:
  13. console.print("❌ [bold red]Failed to locate the 'embedchain' package. Is it installed?[/bold red]")
  14. return
  15. # Construct the source path from the embedchain package
  16. src_path = os.path.join(package_path, "deployment", template)
  17. if not os.path.exists(src_path):
  18. console.print(f"❌ [bold red]Template '{template}' not found.[/bold red]")
  19. return
  20. return src_path
  21. def setup_fly_io_app(extra_args):
  22. fly_launch_command = ["fly", "launch", "--region", "sjc", "--no-deploy"] + list(extra_args)
  23. try:
  24. console.print(f"🚀 [bold cyan]Running: {' '.join(fly_launch_command)}[/bold cyan]")
  25. shutil.move(".env.example", ".env")
  26. subprocess.run(fly_launch_command, check=True)
  27. console.print("✅ [bold green]'fly launch' executed successfully.[/bold green]")
  28. except subprocess.CalledProcessError as e:
  29. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  30. except FileNotFoundError:
  31. console.print(
  32. "❌ [bold red]'fly' command not found. Please ensure Fly CLI is installed and in your PATH.[/bold red]"
  33. )
  34. def setup_modal_com_app(extra_args):
  35. modal_setup_file = os.path.join(os.path.expanduser("~"), ".modal.toml")
  36. if os.path.exists(modal_setup_file):
  37. console.print(
  38. """✅ [bold green]Modal setup already done. You can now install the dependencies by doing \n
  39. `pip install -r requirements.txt`[/bold green]"""
  40. )
  41. else:
  42. modal_setup_cmd = ["modal", "setup"] + list(extra_args)
  43. console.print(f"🚀 [bold cyan]Running: {' '.join(modal_setup_cmd)}[/bold cyan]")
  44. subprocess.run(modal_setup_cmd, check=True)
  45. shutil.move(".env.example", ".env")
  46. console.print(
  47. """Great! Now you can install the dependencies by doing: \n
  48. `pip install -r requirements.txt`\n
  49. \n
  50. To run your app locally:\n
  51. `ec dev`
  52. """
  53. )
  54. def setup_render_com_app():
  55. render_setup_file = os.path.join(os.path.expanduser("~"), ".render/config.yaml")
  56. if os.path.exists(render_setup_file):
  57. console.print(
  58. """✅ [bold green]Render setup already done. You can now install the dependencies by doing \n
  59. `pip install -r requirements.txt`[/bold green]"""
  60. )
  61. else:
  62. render_setup_cmd = ["render", "config", "init"]
  63. console.print(f"🚀 [bold cyan]Running: {' '.join(render_setup_cmd)}[/bold cyan]")
  64. subprocess.run(render_setup_cmd, check=True)
  65. shutil.move(".env.example", ".env")
  66. console.print(
  67. """Great! Now you can install the dependencies by doing: \n
  68. `pip install -r requirements.txt`\n
  69. \n
  70. To run your app locally:\n
  71. `ec dev`
  72. """
  73. )
  74. def setup_streamlit_io_app():
  75. # nothing needs to be done here
  76. console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`")
  77. def setup_gradio_app():
  78. # nothing needs to be done here
  79. console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`")
  80. def setup_hf_app():
  81. subprocess.run(["pip", "install", "huggingface_hub[cli]"], check=True)
  82. hf_setup_file = os.path.join(os.path.expanduser("~"), ".cache/huggingface/token")
  83. if os.path.exists(hf_setup_file):
  84. console.print(
  85. """✅ [bold green]HuggingFace setup already done. You can now install the dependencies by doing \n
  86. `pip install -r requirements.txt`[/bold green]"""
  87. )
  88. else:
  89. console.print(
  90. """🚀 [cyan]Running: huggingface-cli login \n
  91. Please provide a [bold]WRITE[/bold] token so that we can directly deploy\n
  92. your apps from the terminal.[/cyan]
  93. """
  94. )
  95. subprocess.run(["huggingface-cli", "login"], check=True)
  96. console.print("Great! Now you can install the dependencies by doing `pip install -r requirements.txt`")
  97. def run_dev_fly_io(debug, host, port):
  98. uvicorn_command = ["uvicorn", "app:app"]
  99. if debug:
  100. uvicorn_command.append("--reload")
  101. uvicorn_command.extend(["--host", host, "--port", str(port)])
  102. try:
  103. console.print(f"🚀 [bold cyan]Running FastAPI app with command: {' '.join(uvicorn_command)}[/bold cyan]")
  104. subprocess.run(uvicorn_command, check=True)
  105. except subprocess.CalledProcessError as e:
  106. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  107. except KeyboardInterrupt:
  108. console.print("\n🛑 [bold yellow]FastAPI server stopped[/bold yellow]")
  109. def run_dev_modal_com():
  110. modal_run_cmd = ["modal", "serve", "app"]
  111. try:
  112. console.print(f"🚀 [bold cyan]Running FastAPI app with command: {' '.join(modal_run_cmd)}[/bold cyan]")
  113. subprocess.run(modal_run_cmd, check=True)
  114. except subprocess.CalledProcessError as e:
  115. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  116. except KeyboardInterrupt:
  117. console.print("\n🛑 [bold yellow]FastAPI server stopped[/bold yellow]")
  118. def run_dev_streamlit_io():
  119. streamlit_run_cmd = ["streamlit", "run", "app.py"]
  120. try:
  121. console.print(f"🚀 [bold cyan]Running Streamlit app with command: {' '.join(streamlit_run_cmd)}[/bold cyan]")
  122. subprocess.run(streamlit_run_cmd, check=True)
  123. except subprocess.CalledProcessError as e:
  124. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  125. except KeyboardInterrupt:
  126. console.print("\n🛑 [bold yellow]Streamlit server stopped[/bold yellow]")
  127. def run_dev_render_com(debug, host, port):
  128. uvicorn_command = ["uvicorn", "app:app"]
  129. if debug:
  130. uvicorn_command.append("--reload")
  131. uvicorn_command.extend(["--host", host, "--port", str(port)])
  132. try:
  133. console.print(f"🚀 [bold cyan]Running FastAPI app with command: {' '.join(uvicorn_command)}[/bold cyan]")
  134. subprocess.run(uvicorn_command, check=True)
  135. except subprocess.CalledProcessError as e:
  136. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  137. except KeyboardInterrupt:
  138. console.print("\n🛑 [bold yellow]FastAPI server stopped[/bold yellow]")
  139. def run_dev_gradio():
  140. gradio_run_cmd = ["gradio", "app.py"]
  141. try:
  142. console.print(f"🚀 [bold cyan]Running Gradio app with command: {' '.join(gradio_run_cmd)}[/bold cyan]")
  143. subprocess.run(gradio_run_cmd, check=True)
  144. except subprocess.CalledProcessError as e:
  145. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  146. except KeyboardInterrupt:
  147. console.print("\n🛑 [bold yellow]Gradio server stopped[/bold yellow]")
  148. def read_env_file(env_file_path):
  149. """
  150. Reads an environment file and returns a dictionary of key-value pairs.
  151. Args:
  152. env_file_path (str): The path to the .env file.
  153. Returns:
  154. dict: Dictionary of environment variables.
  155. """
  156. env_vars = {}
  157. pattern = re.compile(r"(\w+)=(.*)") # compile regular expression for better performance
  158. with open(env_file_path, "r") as file:
  159. lines = file.readlines() # readlines is faster as it reads all at once
  160. for line in lines:
  161. line = line.strip()
  162. # Ignore comments and empty lines
  163. if line and not line.startswith("#"):
  164. # Assume each line is in the format KEY=VALUE
  165. key_value_match = pattern.match(line)
  166. if key_value_match:
  167. key, value = key_value_match.groups()
  168. env_vars[key] = value
  169. return env_vars
  170. def deploy_fly():
  171. app_name = ""
  172. with open("fly.toml", "r") as file:
  173. for line in file:
  174. if line.strip().startswith("app ="):
  175. app_name = line.split("=")[1].strip().strip('"')
  176. if not app_name:
  177. console.print("❌ [bold red]App name not found in fly.toml[/bold red]")
  178. return
  179. env_vars = read_env_file(".env")
  180. secrets_command = ["flyctl", "secrets", "set", "-a", app_name] + [f"{k}={v}" for k, v in env_vars.items()]
  181. deploy_command = ["fly", "deploy"]
  182. try:
  183. # Set secrets
  184. console.print(f"🔐 [bold cyan]Setting secrets for {app_name}[/bold cyan]")
  185. subprocess.run(secrets_command, check=True)
  186. # Deploy application
  187. console.print(f"🚀 [bold cyan]Running: {' '.join(deploy_command)}[/bold cyan]")
  188. subprocess.run(deploy_command, check=True)
  189. console.print("✅ [bold green]'fly deploy' executed successfully.[/bold green]")
  190. except subprocess.CalledProcessError as e:
  191. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  192. except FileNotFoundError:
  193. console.print(
  194. "❌ [bold red]'fly' command not found. Please ensure Fly CLI is installed and in your PATH.[/bold red]"
  195. )
  196. def deploy_modal():
  197. modal_deploy_cmd = ["modal", "deploy", "app"]
  198. try:
  199. console.print(f"🚀 [bold cyan]Running: {' '.join(modal_deploy_cmd)}[/bold cyan]")
  200. subprocess.run(modal_deploy_cmd, check=True)
  201. console.print("✅ [bold green]'modal deploy' executed successfully.[/bold green]")
  202. except subprocess.CalledProcessError as e:
  203. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  204. except FileNotFoundError:
  205. console.print(
  206. "❌ [bold red]'modal' command not found. Please ensure Modal CLI is installed and in your PATH.[/bold red]"
  207. )
  208. def deploy_streamlit():
  209. streamlit_deploy_cmd = ["streamlit", "run", "app.py"]
  210. try:
  211. console.print(f"🚀 [bold cyan]Running: {' '.join(streamlit_deploy_cmd)}[/bold cyan]")
  212. console.print(
  213. """\n\n✅ [bold yellow]To deploy a streamlit app, you can directly it from the UI.\n
  214. Click on the 'Deploy' button on the top right corner of the app.\n
  215. For more information, please refer to https://docs.embedchain.ai/deployment/streamlit_io
  216. [/bold yellow]
  217. \n\n"""
  218. )
  219. subprocess.run(streamlit_deploy_cmd, check=True)
  220. except subprocess.CalledProcessError as e:
  221. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  222. except FileNotFoundError:
  223. console.print(
  224. """❌ [bold red]'streamlit' command not found.\n
  225. Please ensure Streamlit CLI is installed and in your PATH.[/bold red]"""
  226. )
  227. def deploy_render():
  228. render_deploy_cmd = ["render", "blueprint", "launch"]
  229. try:
  230. console.print(f"🚀 [bold cyan]Running: {' '.join(render_deploy_cmd)}[/bold cyan]")
  231. subprocess.run(render_deploy_cmd, check=True)
  232. console.print("✅ [bold green]'render blueprint launch' executed successfully.[/bold green]")
  233. except subprocess.CalledProcessError as e:
  234. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  235. except FileNotFoundError:
  236. console.print(
  237. "❌ [bold red]'render' command not found. Please ensure Render CLI is installed and in your PATH.[/bold red]" # noqa:E501
  238. )
  239. def deploy_gradio_app():
  240. gradio_deploy_cmd = ["gradio", "deploy"]
  241. try:
  242. console.print(f"🚀 [bold cyan]Running: {' '.join(gradio_deploy_cmd)}[/bold cyan]")
  243. subprocess.run(gradio_deploy_cmd, check=True)
  244. console.print("✅ [bold green]'gradio deploy' executed successfully.[/bold green]")
  245. except subprocess.CalledProcessError as e:
  246. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")
  247. except FileNotFoundError:
  248. console.print(
  249. "❌ [bold red]'gradio' command not found. Please ensure Gradio CLI is installed and in your PATH.[/bold red]" # noqa:E501
  250. )
  251. def deploy_hf_spaces(ec_app_name):
  252. if not ec_app_name:
  253. console.print("❌ [bold red]'name' not found in embedchain.json[/bold red]")
  254. return
  255. hf_spaces_deploy_cmd = ["huggingface-cli", "upload", ec_app_name, ".", ".", "--repo-type=space"]
  256. try:
  257. console.print(f"🚀 [bold cyan]Running: {' '.join(hf_spaces_deploy_cmd)}[/bold cyan]")
  258. subprocess.run(hf_spaces_deploy_cmd, check=True)
  259. console.print("✅ [bold green]'huggingface-cli upload' executed successfully.[/bold green]")
  260. except subprocess.CalledProcessError as e:
  261. console.print(f"❌ [bold red]An error occurred: {e}[/bold red]")