This commit is contained in:
Elijah 2024-11-13 17:12:05 +00:00
parent aa4570175e
commit 5c7c0a49de
2 changed files with 140 additions and 90 deletions

View File

@ -17,7 +17,7 @@ from reflex import constants
from reflex.config import environment, get_config from reflex.config import environment, get_config
from reflex.custom_components.custom_components import custom_components_cli from reflex.custom_components.custom_components import custom_components_cli
from reflex.state import reset_disk_state_manager from reflex.state import reset_disk_state_manager
from reflex.utils import console, redir, telemetry from reflex.utils import console, telemetry
# Disable typer+rich integration for help panels # Disable typer+rich integration for help panels
typer.core.rich = False # type: ignore typer.core.rich = False # type: ignore
@ -98,7 +98,7 @@ def _init(
# Initialize the requirements.txt. # Initialize the requirements.txt.
prerequisites.initialize_requirements_txt() prerequisites.initialize_requirements_txt()
template_msg = "" if template else f" using the {template} template" template_msg = f" using the {template} template" if template else ""
# Finish initializing the app. # Finish initializing the app.
console.success(f"Initialized {app_name}{template_msg}") console.success(f"Initialized {app_name}{template_msg}")

View File

@ -1209,7 +1209,7 @@ def check_schema_up_to_date():
) )
def prompt_for_template(templates: list[Template]) -> str: def prompt_for_template_options(templates: list[Template]) -> str:
"""Prompt the user to specify a template. """Prompt the user to specify a template.
Args: Args:
@ -1378,19 +1378,83 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
shutil.rmtree(unzip_dir) shutil.rmtree(unzip_dir)
def prompt_templates(templates: dict[str, Template]) -> str: def prompt_for_remote_template_selection(templates: dict[str, Template]) -> str:
"""Prompt the user to input a remote template.
Args:
templates: The available templates.
Returns:
The selected template.
Raises:
Exit: If the user does not input a valid template.
"""
while True: while True:
console.print( console.print(
"visit https://reflex.dev/templates for the complete list of templates." "Visit https://reflex.dev/templates for the complete list of templates."
) )
answer = console.ask("Enter a valid template name", show_choices=False) selected_template = console.ask(
if not answer in templates: "Enter a valid template name", show_choices=False
)
if selected_template not in templates:
console.error("Invalid template name. Please try again.") console.error("Invalid template name. Please try again.")
else: else:
return answer return selected_template
def use_ai_generation(template: str | None = None) -> str: def initialize_default_app(app_name: str):
"""Initialize the default app.
Args:
app_name: The name of the app.
"""
create_config(app_name)
initialize_app_directory(app_name)
def validate_and_create_app_using_remote_template(app_name, template, templates):
"""Validate and create an app using a remote template.
Args:
app_name: The name of the app.
template: The name of the template.
templates: The available templates.
Raises:
Exit: If the template is not found.
"""
# If user selects a template, it needs to exist.
if template in templates:
template_url = templates[template].code_url
else:
# Check if the template is a github repo.
if template.startswith("https://github.com"):
template_url = f"{template.strip('/').replace('.git', '')}/archive/main.zip"
else:
console.error(f"Template `{template}` not found.")
raise typer.Exit(1)
if template_url is None:
return
create_config_init_app_from_remote_template(
app_name=app_name, template_url=template_url
)
def generate_template_using_ai(template: str | None = None) -> str:
"""Generate a template using AI(Flexgen).
Args:
template: The name of the template.
Returns:
The generation hash.
Raises:
Exit: If the template and ai flags are used.
"""
if template is None: if template is None:
# If AI is requested and no template specified, redirect the user to reflex.build. # If AI is requested and no template specified, redirect the user to reflex.build.
return redir.reflex_build_redirect() return redir.reflex_build_redirect()
@ -1404,6 +1468,42 @@ def use_ai_generation(template: str | None = None) -> str:
raise typer.Exit(2) raise typer.Exit(2)
def fetch_and_prompt_with_remote_templates(
template: str, show_prompt: bool = True
) -> tuple[str, dict[str, Template]]:
"""Fetch the available remote templates and prompt the user for an input.
Args:
template: The name of the template.
show_prompt: Whether to show the prompt.
Returns:
The selected template and the available templates.
"""
available_templates = {}
try:
# Get the available templates
available_templates = fetch_app_templates(constants.Reflex.VERSION)
if not show_prompt and template in available_templates:
return template, available_templates
if not show_prompt and (template not in templates):
console.error(f"{template} is not a valid template name.")
template = (
prompt_for_remote_template_selection(available_templates)
if available_templates
else constants.Templates.DEFAULT
)
except Exception as e:
console.warn("Failed to fetch templates. Falling back to default template.")
console.debug(f"Error while fetching templates: {e}")
return (template or constants.Templates.DEFAULT), available_templates
def initialize_app( def initialize_app(
app_name: str, template: str | None = None, ai: bool = False app_name: str, template: str | None = None, ai: bool = False
) -> str | None: ) -> str | None:
@ -1412,6 +1512,7 @@ def initialize_app(
Args: Args:
app_name: The name of the app. app_name: The name of the app.
template: The name of the template to use. template: The name of the template to use.
ai: Whether to use AI to generate the template.
Raises: Raises:
Exit: If template is directly provided in the command flag and is invalid. Exit: If template is directly provided in the command flag and is invalid.
@ -1429,102 +1530,51 @@ def initialize_app(
generation_hash = None generation_hash = None
if ai: if ai:
generation_hash = use_ai_generation(template) generation_hash = generate_template_using_ai(template)
template = constants.Templates.AI template = constants.Templates.DEFAULT
templates: dict[str, Template] = {} templates: dict[str, Template] = {}
# Don't fetch app templates if the user directly asked for DEFAULT. # Don't fetch app templates if the user directly asked for DEFAULT.
if template is not None and ( if template is not None and (template not in (constants.Templates.DEFAULT,)):
template != constants.Templates.DEFAULT or template != constants.Templates.AI template, templates = fetch_and_prompt_with_remote_templates(
): template, show_prompt=False
try: )
# Get the available templates
templates = fetch_app_templates(constants.Reflex.VERSION) if template is None:
if template is None and len(templates) > 0: template = prompt_for_template_options(get_init_cli_prompt_options())
template = prompt_for_template(list(templates.values())) if template == constants.Templates.AI:
except Exception as e: generation_hash = generate_template_using_ai()
console.warn("Failed to fetch templates. Falling back to default template.") # change to the default to allow creation of default app
console.debug(f"Error while fetching templates: {e}") template = constants.Templates.DEFAULT
finally: elif template == constants.Templates.CHOOSE_TEMPLATES:
template = template or constants.Templates.DEFAULT template, templates = fetch_and_prompt_with_remote_templates(template)
if template is None: # If the blank template is selected, create a blank app.
template = prompt_for_template(get_init_cli_options()) if template in (constants.Templates.DEFAULT,):
if template == constants.Templates.AI: # Default app creation behavior: a blank app.
generation_hash = use_ai_generation() initialize_default_app(app_name)
elif template == constants.Templates.CHOOSE_TEMPLATES: else:
try: validate_and_create_app_using_remote_template(
# Get the available templates app_name=app_name, template=template, templates=templates
templates = fetch_app_templates(constants.Reflex.VERSION)
# default to the blank template if no templates are available
template = (
prompt_templates(templates)
if len(templates) > 0
else constants.Templates.DEFAULT
)
except Exception as e:
console.warn(
"Failed to fetch templates. Falling back to default template."
)
console.debug(f"Error while fetching templates: {e}")
template = constants.Templates.DEFAULT
else:
console.error("Invalid option selected.")
raise typer.Exit(2)
# If the blank template is selected, create a blank app.
if template == constants.Templates.DEFAULT or template == constants.Templates.AI:
# Default app creation behavior: a blank app.
create_config(app_name)
initialize_app_directory(app_name)
else:
# If user selects a template, it needs to exist.
if template in templates:
template_url = templates[template].code_url
else:
# Check if the template is a github repo.
if template.startswith("https://github.com"):
template_url = (
f"{template.strip('/').replace('.git', '')}/archive/main.zip"
)
else:
console.error(f"Template `{template}` not found.")
raise typer.Exit(1)
if template_url is None:
return
create_config_init_app_from_remote_template(
app_name=app_name, template_url=template_url
) )
telemetry.send("init", template=template)
# If a reflex.build generation hash is available, download the code and apply it to the main module. # If a reflex.build generation hash is available, download the code and apply it to the main module.
if generation_hash: if generation_hash:
initialize_main_module_index_from_generation( initialize_main_module_index_from_generation(
app_name, generation_hash=generation_hash app_name, generation_hash=generation_hash
) )
telemetry.send("init", template=template)
return template return template
def fetch_and_prompt_for_templates( def get_init_cli_prompt_options() -> list[Template]:
template: str | None, templates: dict[str, Template] """Get the CLI options for initializing a Reflex app.
) -> str:
"""Fetches available templates and prompts the user if template is not specified."""
try:
templates = fetch_app_templates(constants.Reflex.VERSION)
if not template and templates:
template = prompt_for_template(list(templates.values()))
except Exception as e:
console.warn("Failed to fetch templates. Falling back to default template.")
console.debug(f"Error while fetching templates: {e}")
return template or constants.Templates.DEFAULT
Returns:
def get_init_cli_options() -> list[Template]: The CLI options.
"""
return [ return [
Template( Template(
name=constants.Templates.DEFAULT, name=constants.Templates.DEFAULT,
@ -1534,7 +1584,7 @@ def get_init_cli_options() -> list[Template]:
), ),
Template( Template(
name=constants.Templates.AI, name=constants.Templates.AI,
description="Generate a template using AI(Flexgen)", description="Generate a template using AI (Flexgen)",
demo_url="https://flexgen.reflex.run", demo_url="https://flexgen.reflex.run",
code_url="", code_url="",
), ),