mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-19 21:33:51 +00:00
parent
9f85f7c543
commit
d9018ae5f1
@ -1,5 +1,12 @@
|
|||||||
"""A CLI for creating a new project with LangChain."""
|
"""A CLI for creating a new project with LangChain."""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from typing_extensions import Annotated
|
||||||
|
|
||||||
|
from langchain.cli.create_repo.base import create, is_poetry_installed
|
||||||
|
from langchain.cli.create_repo.pypi_name import is_name_taken, lint_name
|
||||||
|
from langchain.cli.create_repo.user_info import get_git_user_email, get_git_user_name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import typer
|
import typer
|
||||||
@ -9,45 +16,94 @@ except ImportError:
|
|||||||
"You can install it with `pip install typer`."
|
"You can install it with `pip install typer`."
|
||||||
)
|
)
|
||||||
|
|
||||||
from typing_extensions import Annotated
|
|
||||||
|
|
||||||
from langchain.cli.create_repo.base import create, is_poetry_installed
|
|
||||||
from langchain.cli.create_repo.user_info import get_git_user_email, get_git_user_name
|
|
||||||
|
|
||||||
app = typer.Typer(no_args_is_help=False, add_completion=False)
|
app = typer.Typer(no_args_is_help=False, add_completion=False)
|
||||||
|
|
||||||
|
|
||||||
AUTHOR_NAME_OPTION = typer.Option(
|
def _select_project_name(suggested_project_name: str) -> str:
|
||||||
default_factory=get_git_user_name,
|
"""Help the user select a valid project name."""
|
||||||
prompt=True,
|
while True:
|
||||||
help="If not specified, will be inferred from git config if possible. ",
|
project_name = typer.prompt("Project Name", default=suggested_project_name)
|
||||||
)
|
|
||||||
AUTHOR_EMAIL_OPTION = typer.Option(
|
project_name_diagnostics = lint_name(project_name)
|
||||||
default_factory=get_git_user_email,
|
if project_name_diagnostics:
|
||||||
prompt=True,
|
typer.echo(
|
||||||
help="If not specified, will be inferred from git config if possible. ",
|
f"{typer.style('Warning:', fg=typer.colors.MAGENTA)}"
|
||||||
)
|
f" The project name"
|
||||||
USE_POETRY_OPTION = typer.Option(
|
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
||||||
default_factory=is_poetry_installed,
|
f" is not valid.",
|
||||||
prompt=True,
|
err=True,
|
||||||
help=(
|
)
|
||||||
"Whether to use Poetry to manage the project. "
|
|
||||||
"If not specified, Poetry will be used if poetry is installed."
|
for diagnostic in project_name_diagnostics:
|
||||||
),
|
typer.echo(f" - {diagnostic}")
|
||||||
)
|
|
||||||
|
if typer.confirm(
|
||||||
|
"Select another name?",
|
||||||
|
default=True,
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if is_name_taken(project_name):
|
||||||
|
typer.echo(
|
||||||
|
f"{typer.style('Error:', fg=typer.colors.RED)}"
|
||||||
|
f" The project name"
|
||||||
|
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
||||||
|
f" is already taken on pypi",
|
||||||
|
err=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if typer.confirm(
|
||||||
|
"Select another name?",
|
||||||
|
default=True,
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If we got here then the project name is valid and not taken
|
||||||
|
return project_name
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
@app.command()
|
@app.command()
|
||||||
def new(
|
def new(
|
||||||
project_directory: Annotated[
|
project_directory: Annotated[
|
||||||
Path, typer.Argument(help="The directory to create the project in.")
|
Path, typer.Argument(help="The directory to create the project in.")
|
||||||
],
|
],
|
||||||
author_name: Annotated[str, AUTHOR_NAME_OPTION],
|
author_name: Optional[str] = None,
|
||||||
author_email: Annotated[str, AUTHOR_EMAIL_OPTION],
|
author_email: Optional[str] = None,
|
||||||
use_poetry: Annotated[bool, USE_POETRY_OPTION],
|
use_poetry: Annotated[
|
||||||
|
Optional[bool], typer.Option(help="Specify whether to use Poetry or not.")
|
||||||
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a new project with LangChain."""
|
"""Create a new project with LangChain."""
|
||||||
create(project_directory, author_name, author_email, use_poetry)
|
|
||||||
|
project_directory_path = Path(project_directory)
|
||||||
|
project_name_suggestion = project_directory_path.name.replace("-", "_")
|
||||||
|
project_name = _select_project_name(project_name_suggestion)
|
||||||
|
|
||||||
|
if not author_name:
|
||||||
|
author_name = typer.prompt("Author Name", default=get_git_user_name())
|
||||||
|
|
||||||
|
if not author_email:
|
||||||
|
author_email = typer.prompt("Author Email", default=get_git_user_email())
|
||||||
|
|
||||||
|
if use_poetry is None:
|
||||||
|
if is_poetry_installed():
|
||||||
|
typer.echo("🎉 Found Poetry installed. Project can be set up using poetry.")
|
||||||
|
use_poetry = typer.confirm("Use Poetry? (no to use pip)", default=True)
|
||||||
|
else:
|
||||||
|
typer.echo("ℹ️ Could not find Poetry installed.")
|
||||||
|
use_pip = typer.confirm("Use Pip? (no to use poetry)", default=True)
|
||||||
|
use_poetry = not use_pip
|
||||||
|
|
||||||
|
if author_name is None:
|
||||||
|
raise typer.BadParameter("Author name is required")
|
||||||
|
|
||||||
|
if author_email is None:
|
||||||
|
raise typer.BadParameter("Author email is required")
|
||||||
|
|
||||||
|
create(project_directory, project_name, author_name, author_email, use_poetry)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -9,7 +9,6 @@ from typing import List, Sequence
|
|||||||
import typer
|
import typer
|
||||||
|
|
||||||
import langchain
|
import langchain
|
||||||
from langchain.cli.create_repo.pypi_name import is_name_taken, lint_name
|
|
||||||
|
|
||||||
|
|
||||||
class UnderscoreTemplate(string.Template):
|
class UnderscoreTemplate(string.Template):
|
||||||
@ -145,7 +144,7 @@ def _pip_install(project_directory_path: Path) -> None:
|
|||||||
def _init_git(project_directory_path: Path) -> None:
|
def _init_git(project_directory_path: Path) -> None:
|
||||||
"""Initialize git repository."""
|
"""Initialize git repository."""
|
||||||
typer.echo(
|
typer.echo(
|
||||||
f"\n{typer.style('3.', bold=True, fg=typer.colors.GREEN)} Initializing git..."
|
f"\n{typer.style('Initializing git...', bold=True, fg=typer.colors.GREEN)}"
|
||||||
)
|
)
|
||||||
subprocess.run(["git", "init"], cwd=project_directory_path)
|
subprocess.run(["git", "init"], cwd=project_directory_path)
|
||||||
|
|
||||||
@ -157,58 +156,12 @@ def _init_git(project_directory_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _select_project_name(suggested_project_name: str) -> str:
|
|
||||||
"""Help the user select a valid project name."""
|
|
||||||
while True:
|
|
||||||
project_name = typer.prompt(
|
|
||||||
"Please choose a project name: ", default=suggested_project_name
|
|
||||||
)
|
|
||||||
|
|
||||||
project_name_diagnostics = lint_name(project_name)
|
|
||||||
if project_name_diagnostics:
|
|
||||||
typer.echo(
|
|
||||||
f"{typer.style('Error:', fg=typer.colors.RED)}"
|
|
||||||
f" The project name"
|
|
||||||
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
|
||||||
f" is not valid:",
|
|
||||||
err=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
for diagnostic in project_name_diagnostics:
|
|
||||||
typer.echo(f" - {diagnostic}")
|
|
||||||
|
|
||||||
if typer.confirm(
|
|
||||||
"Would you like to choose another name? "
|
|
||||||
"Choose NO to proceed with existing name.",
|
|
||||||
default=True,
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if is_name_taken(project_name):
|
|
||||||
typer.echo(
|
|
||||||
f"{typer.style('Error:', fg=typer.colors.RED)}"
|
|
||||||
f" The project name"
|
|
||||||
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
|
||||||
f" is already taken on pypi",
|
|
||||||
err=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
if typer.confirm(
|
|
||||||
"Would you like to choose another name? "
|
|
||||||
"Choose NO to proceed with existing name.",
|
|
||||||
default=True,
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# If we got here then the project name is valid and not taken
|
|
||||||
return project_name
|
|
||||||
|
|
||||||
|
|
||||||
# PUBLIC API
|
# PUBLIC API
|
||||||
|
|
||||||
|
|
||||||
def create(
|
def create(
|
||||||
project_directory: pathlib.Path,
|
project_directory: pathlib.Path,
|
||||||
|
project_name: str,
|
||||||
author_name: str,
|
author_name: str,
|
||||||
author_email: str,
|
author_email: str,
|
||||||
use_poetry: bool,
|
use_poetry: bool,
|
||||||
@ -217,27 +170,29 @@ def create(
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
project_directory (str): The directory to create the project in.
|
project_directory (str): The directory to create the project in.
|
||||||
|
project_name: The name of the project.
|
||||||
author_name (str): The name of the author.
|
author_name (str): The name of the author.
|
||||||
author_email (str): The email of the author.
|
author_email (str): The email of the author.
|
||||||
use_poetry (bool): Whether to use Poetry to manage the project.
|
use_poetry (bool): Whether to use Poetry to manage the project.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
project_directory_path = Path(project_directory)
|
project_directory_path = Path(project_directory)
|
||||||
project_name_suggestion = project_directory_path.name.replace("-", "_")
|
|
||||||
project_name = _select_project_name(project_name_suggestion)
|
|
||||||
project_name_identifier = project_name
|
project_name_identifier = project_name
|
||||||
|
|
||||||
resolved_path = project_directory_path.resolve()
|
resolved_path = project_directory_path.resolve()
|
||||||
|
|
||||||
if not typer.confirm(
|
if not typer.confirm(
|
||||||
f"\n{typer.style('>', bold=True, fg=typer.colors.GREEN)} "
|
f"\n"
|
||||||
f"Creating new LangChain project "
|
f"Creating a new LangChain project 🦜️🔗\n"
|
||||||
f"{typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
f"Name: {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}\n"
|
||||||
f" in"
|
f"Path: {typer.style(resolved_path, fg=typer.colors.BRIGHT_CYAN)}\n"
|
||||||
f" {typer.style(resolved_path, fg=typer.colors.BRIGHT_CYAN)}",
|
f"Project name: {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}\n"
|
||||||
|
f"Author name: {typer.style(author_name, fg=typer.colors.BRIGHT_CYAN)}\n"
|
||||||
|
f"Author email: {typer.style(author_email, fg=typer.colors.BRIGHT_CYAN)}\n"
|
||||||
|
f"Use Poetry: {typer.style(str(use_poetry), fg=typer.colors.BRIGHT_CYAN)}\n"
|
||||||
|
"Continue?",
|
||||||
default=True,
|
default=True,
|
||||||
):
|
):
|
||||||
typer.echo("OK! Canceling project creation.")
|
typer.echo("Cancelled project creation. See you later! 👋")
|
||||||
raise typer.Exit(code=0)
|
raise typer.Exit(code=0)
|
||||||
|
|
||||||
_create_project_dir(
|
_create_project_dir(
|
||||||
@ -258,7 +213,7 @@ def create(
|
|||||||
_init_git(project_directory_path)
|
_init_git(project_directory_path)
|
||||||
|
|
||||||
typer.echo(
|
typer.echo(
|
||||||
f"\n{typer.style('Done!', bold=True, fg=typer.colors.GREEN)}"
|
f"\n{typer.style('Done!🙌', bold=True, fg=typer.colors.GREEN)}"
|
||||||
f" Your new LangChain project"
|
f" Your new LangChain project"
|
||||||
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
||||||
f" has been created in"
|
f" has been created in"
|
||||||
|
Loading…
Reference in New Issue
Block a user