[Feature] Add render.com deployment template (#1033)

Co-authored-by: Deven Patel <iamdevenpatel@gmail.com>
This commit is contained in:
Sidharth Mohanty
2023-12-20 22:38:23 +05:30
committed by GitHub
parent 7ee2d0653b
commit 737837ae0b
9 changed files with 233 additions and 61 deletions

View File

@@ -43,6 +43,7 @@ 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:
@@ -60,12 +61,41 @@ def setup_modal_com_app(extra_args):
"""✅ [bold green]Modal setup already done. You can now install the dependencies by doing \n
`pip install -r requirements.txt`[/bold green]"""
)
return
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)
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 `pip install -r requirements.txt`")
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`
"""
)
@cli.command()
@@ -75,15 +105,14 @@ 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)
env_sample_path = os.path.join(src_path, ".env.example")
if os.path.exists(env_sample_path):
shutil.copy(env_sample_path, os.path.join(os.getcwd(), ".env"))
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()
else:
raise ValueError(f"Unknown template '{template}'.")
@@ -123,6 +152,23 @@ def run_dev_modal_com():
console.print("\n🛑 [bold yellow]FastAPI 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.")
@@ -138,6 +184,8 @@ def dev(debug, host, port):
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)
else:
raise ValueError(f"Unknown template '{template}'.")
@@ -212,6 +260,21 @@ def deploy_modal():
)
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
@@ -225,5 +288,7 @@ def deploy():
deploy_fly()
elif template == "modal.com":
deploy_modal()
elif template == "render.com":
deploy_render()
else:
console.print("❌ [bold red]No recognized deployment platform found.[/bold red]")

View File

@@ -0,0 +1 @@
OPENAI_API_KEY=sk-xxx

View File

@@ -0,0 +1 @@
.env

View File

@@ -1,58 +1,53 @@
import logging
import os
from fastapi import FastAPI, responses
from pydantic import BaseModel
from flask import Flask, jsonify, request
from embedchain import Pipeline
from embedchain import Pipeline as App
app = Flask(__name__)
os.environ["OPENAI_API_KEY"] = "sk-xxx"
app = FastAPI(title="Embedchain FastAPI App")
embedchain_app = Pipeline()
@app.route("/add", methods=["POST"])
def add():
data = request.get_json()
data_type = data.get("data_type")
url_or_text = data.get("url_or_text")
if data_type and url_or_text:
try:
App().add(url_or_text, data_type=data_type)
return jsonify({"data": f"Added {data_type}: {url_or_text}"}), 200
except Exception:
logging.exception(f"Failed to add {data_type=}: {url_or_text=}")
return jsonify({"error": f"Failed to add {data_type}: {url_or_text}"}), 500
return jsonify({"error": "Invalid request. Please provide 'data_type' and 'url_or_text' in JSON format."}), 400
class SourceModel(BaseModel):
source: str
@app.route("/query", methods=["POST"])
def query():
data = request.get_json()
question = data.get("question")
if question:
try:
response = App().query(question)
return jsonify({"data": response}), 200
except Exception:
logging.exception(f"Failed to query {question=}")
return jsonify({"error": "An error occurred. Please try again!"}), 500
return jsonify({"error": "Invalid request. Please provide 'question' in JSON format."}), 400
class QuestionModel(BaseModel):
question: str
@app.route("/chat", methods=["POST"])
def chat():
data = request.get_json()
question = data.get("question")
if question:
try:
response = App().chat(question)
return jsonify({"data": response}), 200
except Exception:
logging.exception(f"Failed to chat {question=}")
return jsonify({"error": "An error occurred. Please try again!"}), 500
return jsonify({"error": "Invalid request. Please provide 'question' in JSON format."}), 400
@app.post("/add")
async def add_source(source_model: SourceModel):
"""
Adds a new source to the EmbedChain app.
Expects a JSON with a "source" key.
"""
source = source_model.source
embedchain_app.add(source)
return {"message": f"Source '{source}' added successfully."}
@app.route("/api/python")
def hello_world():
return "<p>Hello, World!</p>"
@app.post("/query")
async def handle_query(question_model: QuestionModel):
"""
Handles a query to the EmbedChain app.
Expects a JSON with a "question" key.
"""
question = question_model.question
answer = embedchain_app.query(question)
return {"answer": answer}
@app.post("/chat")
async def handle_chat(question_model: QuestionModel):
"""
Handles a chat request to the EmbedChain app.
Expects a JSON with a "question" key.
"""
question = question_model.question
response = embedchain_app.chat(question)
return {"response": response}
@app.get("/")
async def root():
return responses.RedirectResponse(url="/docs")

View File

@@ -0,0 +1,16 @@
services:
- type: web
name: ec-render-app
runtime: python
repo: https://github.com/<your-username>/<repo-name>
scaling:
minInstances: 1
maxInstances: 3
targetMemoryPercent: 60 # optional if targetCPUPercent is set
targetCPUPercent: 60 # optional if targetMemory is set
buildCommand: pip install -r requirements.txt
startCommand: uvicorn app:app --host 0.0.0.0
envVars:
- key: OPENAI_API_KEY
value: sk-xxx
autoDeploy: false # optional

View File

@@ -1,5 +1,4 @@
numpy==1.24.3
Flask==2.2.2
Werkzeug==2.2.2
gunicorn
fastapi==0.104.0
uvicorn==0.23.2
embedchain
beautifulsoup4