mirror of https://github.com/hwchase17/langchain
Remove CLI (#12283)
<!-- Thank you for contributing to LangChain! Replace this entire comment with: - **Description:** a description of the change, - **Issue:** the issue # it fixes (if applicable), - **Dependencies:** any dependencies required for this change, - **Tag maintainer:** for a quicker response, tag the relevant maintainer (see below), - **Twitter handle:** we announce bigger features on Twitter. If your PR gets announced, and you'd like a mention, we'll gladly shout you out! Please make sure your PR is passing linting and testing before submitting. Run `make format`, `make lint` and `make test` to check this locally. See contribution guidelines for more information on how to write/run tests, lint, etc: https://github.com/langchain-ai/langchain/blob/master/.github/CONTRIBUTING.md If you're adding a new integration, please include: 1. a test for the integration, preferably unit tests that do not rely on network access, 2. an example notebook showing its use. It lives in `docs/extras` directory. If no one reviews your PR within a few days, please @-mention one of @baskaryan, @eyurtsev, @hwchase17. -->pull/12286/head
parent
b5b2d07681
commit
7108084947
@ -1,266 +0,0 @@
|
|||||||
""""""
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import string
|
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import List, Sequence
|
|
||||||
|
|
||||||
import typer
|
|
||||||
|
|
||||||
import langchain
|
|
||||||
|
|
||||||
|
|
||||||
class UnderscoreTemplate(string.Template):
|
|
||||||
delimiter = "____"
|
|
||||||
|
|
||||||
|
|
||||||
def _create_project_dir(
|
|
||||||
project_directory_path: Path,
|
|
||||||
use_poetry: bool,
|
|
||||||
project_name: str,
|
|
||||||
project_name_identifier: str,
|
|
||||||
author_name: str,
|
|
||||||
author_email: str,
|
|
||||||
) -> None:
|
|
||||||
project_directory_path.mkdir(parents=True, exist_ok=True)
|
|
||||||
template_directories = _get_template_directories(use_poetry)
|
|
||||||
_check_conflicting_files(template_directories, project_directory_path)
|
|
||||||
_copy_template_files(
|
|
||||||
template_directories,
|
|
||||||
project_directory_path,
|
|
||||||
project_name,
|
|
||||||
project_name_identifier,
|
|
||||||
author_name,
|
|
||||||
author_email,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_template_directories(use_poetry: bool) -> List[Path]:
|
|
||||||
"""Get the directories containing the templates.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
use_poetry: If true, will set up the project with Poetry.
|
|
||||||
|
|
||||||
"""
|
|
||||||
template_parent_path = Path(__file__).parent / "templates"
|
|
||||||
template_directories = [template_parent_path / "repo"]
|
|
||||||
if use_poetry:
|
|
||||||
template_directories.append(template_parent_path / "poetry")
|
|
||||||
else:
|
|
||||||
template_directories.append(template_parent_path / "pip")
|
|
||||||
return template_directories
|
|
||||||
|
|
||||||
|
|
||||||
def _check_conflicting_files(
|
|
||||||
template_directories: Sequence[Path], project_directory_path: Path
|
|
||||||
) -> None:
|
|
||||||
"""Validate project directory doesn't contain conflicting files."""
|
|
||||||
|
|
||||||
for template_directory_path in template_directories:
|
|
||||||
for template_file_path in template_directory_path.glob("**/*"):
|
|
||||||
relative_template_file_path = template_file_path.relative_to(
|
|
||||||
template_directory_path
|
|
||||||
)
|
|
||||||
project_file_path = project_directory_path / relative_template_file_path
|
|
||||||
if project_file_path.exists():
|
|
||||||
typer.echo(
|
|
||||||
f"{typer.style('Error:', fg=typer.colors.RED)}"
|
|
||||||
f" The project directory already contains a file"
|
|
||||||
f" {typer.style(project_file_path, fg=typer.colors.BRIGHT_CYAN)}"
|
|
||||||
f" that would be overwritten by the template.",
|
|
||||||
err=True,
|
|
||||||
)
|
|
||||||
typer.echo(
|
|
||||||
"Please remove this file and try again.",
|
|
||||||
err=True,
|
|
||||||
)
|
|
||||||
raise typer.Exit(code=1)
|
|
||||||
|
|
||||||
|
|
||||||
def _copy_template_files(
|
|
||||||
template_directories: Sequence[Path],
|
|
||||||
project_directory_path: Path,
|
|
||||||
project_name: str,
|
|
||||||
project_name_identifier: str,
|
|
||||||
author_name: str,
|
|
||||||
author_email: str,
|
|
||||||
) -> None:
|
|
||||||
"""Copy template files to project directory and substitute variables.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
template_directories: The directories containing the templates.
|
|
||||||
project_directory_path: The destination directory.
|
|
||||||
project_name: The name of the project.
|
|
||||||
project_name_identifier: The identifier of the project name.
|
|
||||||
author_name: The name of the author.
|
|
||||||
author_email: The email of the author.
|
|
||||||
"""
|
|
||||||
for template_directory_path in template_directories:
|
|
||||||
for template_file_path in template_directory_path.glob("**/*"):
|
|
||||||
# Ignore __pycache__ directories and their contents
|
|
||||||
if "__pycache__" in template_file_path.parts:
|
|
||||||
continue
|
|
||||||
|
|
||||||
relative_template_file_path = UnderscoreTemplate(
|
|
||||||
str(template_file_path.relative_to(template_directory_path))
|
|
||||||
).substitute(project_name_identifier=project_name_identifier)
|
|
||||||
project_file_path = project_directory_path / relative_template_file_path
|
|
||||||
if template_file_path.is_dir():
|
|
||||||
project_file_path.mkdir(parents=True, exist_ok=True)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
content = template_file_path.read_text(encoding="utf-8")
|
|
||||||
except UnicodeDecodeError as e:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Encountered an error while reading a "
|
|
||||||
f"template file {template_file_path}"
|
|
||||||
) from e
|
|
||||||
|
|
||||||
project_file_path.write_text(
|
|
||||||
UnderscoreTemplate(content).substitute(
|
|
||||||
project_name=project_name,
|
|
||||||
project_name_identifier=project_name_identifier,
|
|
||||||
author_name=author_name,
|
|
||||||
author_email=author_email,
|
|
||||||
langchain_version=langchain.__version__,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _poetry_install(project_directory_path: Path) -> None:
|
|
||||||
"""Install dependencies with Poetry."""
|
|
||||||
typer.echo(
|
|
||||||
f"\n{typer.style('2.', bold=True, fg=typer.colors.GREEN)}"
|
|
||||||
f" Installing dependencies with Poetry..."
|
|
||||||
)
|
|
||||||
subprocess.run(["pwd"], cwd=project_directory_path)
|
|
||||||
subprocess.run(
|
|
||||||
["poetry", "install"],
|
|
||||||
cwd=project_directory_path,
|
|
||||||
env={**os.environ.copy(), "VIRTUAL_ENV": ""},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _pip_install(project_directory_path: Path) -> None:
|
|
||||||
"""Create virtual environment and install dependencies."""
|
|
||||||
typer.echo(
|
|
||||||
f"\n{typer.style('2.', bold=True, fg=typer.colors.GREEN)}"
|
|
||||||
f" Creating virtual environment..."
|
|
||||||
)
|
|
||||||
subprocess.run(["pwd"], cwd=project_directory_path)
|
|
||||||
subprocess.run(["python", "-m", "venv", ".venv"], cwd=project_directory_path)
|
|
||||||
# TODO install dependencies
|
|
||||||
|
|
||||||
|
|
||||||
def _init_git(project_directory_path: Path) -> None:
|
|
||||||
"""Initialize git repository."""
|
|
||||||
typer.echo(
|
|
||||||
f"\n{typer.style('Initializing git...', bold=True, fg=typer.colors.GREEN)}"
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
subprocess.run(["git", "init"], cwd=project_directory_path)
|
|
||||||
except FileNotFoundError:
|
|
||||||
typer.echo("Git not found. Skipping git initialization.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 7. Create initial commit
|
|
||||||
subprocess.run(["git", "add", "."], cwd=project_directory_path)
|
|
||||||
subprocess.run(
|
|
||||||
["git", "commit", "-m", "Initial commit"],
|
|
||||||
cwd=project_directory_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# PUBLIC API
|
|
||||||
|
|
||||||
|
|
||||||
def create(
|
|
||||||
project_directory: pathlib.Path,
|
|
||||||
project_name: str,
|
|
||||||
author_name: str,
|
|
||||||
author_email: str,
|
|
||||||
use_poetry: bool,
|
|
||||||
) -> None:
|
|
||||||
"""Create a new LangChain project.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
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_email (str): The email of the author.
|
|
||||||
use_poetry (bool): Whether to use Poetry to manage the project.
|
|
||||||
"""
|
|
||||||
|
|
||||||
project_directory_path = Path(project_directory)
|
|
||||||
project_name_identifier = project_name
|
|
||||||
resolved_path = project_directory_path.resolve()
|
|
||||||
|
|
||||||
if not typer.confirm(
|
|
||||||
f"\n"
|
|
||||||
f"Creating a new LangChain project 🦜️🔗\n"
|
|
||||||
f"Name: {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}\n"
|
|
||||||
f"Path: {typer.style(resolved_path, fg=typer.colors.BRIGHT_CYAN)}\n"
|
|
||||||
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,
|
|
||||||
):
|
|
||||||
typer.echo("Cancelled project creation. See you later! 👋")
|
|
||||||
raise typer.Exit(code=0)
|
|
||||||
|
|
||||||
_create_project_dir(
|
|
||||||
project_directory_path,
|
|
||||||
use_poetry,
|
|
||||||
project_name,
|
|
||||||
project_name_identifier,
|
|
||||||
author_name,
|
|
||||||
author_email,
|
|
||||||
)
|
|
||||||
|
|
||||||
# TODO(Team): Add installation
|
|
||||||
# if use_poetry:
|
|
||||||
# _poetry_install(project_directory_path)
|
|
||||||
# else:
|
|
||||||
# _pip_install(project_directory_path)
|
|
||||||
|
|
||||||
_init_git(project_directory_path)
|
|
||||||
|
|
||||||
typer.echo(
|
|
||||||
f"\n{typer.style('Done!🙌', bold=True, fg=typer.colors.GREEN)}"
|
|
||||||
f" Your new LangChain project"
|
|
||||||
f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}"
|
|
||||||
f" has been created in"
|
|
||||||
f" {typer.style(project_directory_path.resolve(), fg=typer.colors.BRIGHT_CYAN)}"
|
|
||||||
f"."
|
|
||||||
)
|
|
||||||
# TODO(Team): Add surfacing information from make file and installation
|
|
||||||
# cd_dir = typer.style(
|
|
||||||
# f"cd {project_directory_path.resolve()}", fg=typer.colors.BRIGHT_CYAN
|
|
||||||
# )
|
|
||||||
# typer.echo(
|
|
||||||
# f"\nChange into the project directory with {cd_dir}."
|
|
||||||
# f" The following commands are available:"
|
|
||||||
# )
|
|
||||||
# subprocess.run(["make"], cwd=project_directory_path)
|
|
||||||
|
|
||||||
# if not use_poetry:
|
|
||||||
# pip_install = typer.style(
|
|
||||||
# 'pip install -e ".[dev]"', fg=typer.colors.BRIGHT_CYAN
|
|
||||||
# )
|
|
||||||
# typer.echo(
|
|
||||||
# f"\nTo install all dependencies activate your environment run:"
|
|
||||||
# f"\n{typer.style('source .venv/bin/activate', fg=typer.colors.BRIGHT_CYAN)}"
|
|
||||||
# f"\n{pip_install}."
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
def is_poetry_installed() -> bool:
|
|
||||||
"""Check if Poetry is installed."""
|
|
||||||
try:
|
|
||||||
result = subprocess.run(["poetry", "--version"], capture_output=True)
|
|
||||||
return result.returncode == 0
|
|
||||||
except FileNotFoundError:
|
|
||||||
return False
|
|
@ -1,70 +0,0 @@
|
|||||||
"""Code helps to check availability of the name of the project on PyPi
|
|
||||||
|
|
||||||
Adapted from https://github.com/danishprakash/pip-name/blob/master/pip-name
|
|
||||||
"""
|
|
||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
BASE_URL = "https://pypi.org/pypi"
|
|
||||||
|
|
||||||
UPPERCASE_SUGGESTION = "Use of uppercase letters is discouraged"
|
|
||||||
SEPARATOR_SUGGESTION = "Use of `-` is discouraged, consider using `_`"
|
|
||||||
NUMERIC_SUGGESTION = "Use of numbers is discouraged"
|
|
||||||
|
|
||||||
|
|
||||||
def _request_pypi(name: str) -> Optional[dict]:
|
|
||||||
"""Request response from PyPi API.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name (str): Name of the project
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Optional[dict]: Response from PyPi API
|
|
||||||
"""
|
|
||||||
target_url = f"{BASE_URL}/{name}/json"
|
|
||||||
response = requests.get(target_url)
|
|
||||||
return response.json() if response.status_code != 404 else None
|
|
||||||
|
|
||||||
|
|
||||||
# PUBLIC API
|
|
||||||
|
|
||||||
|
|
||||||
def lint_name(name: str) -> List[str]:
|
|
||||||
"""Check name against PEP8's naming conventions.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name (str): Name of the project
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[str]: List of suggestions
|
|
||||||
"""
|
|
||||||
suggestions = []
|
|
||||||
|
|
||||||
if "-" in name or " " in name:
|
|
||||||
suggestions.append(SEPARATOR_SUGGESTION)
|
|
||||||
if any(x.isupper() for x in name):
|
|
||||||
suggestions.append(UPPERCASE_SUGGESTION)
|
|
||||||
if any(x.isnumeric() for x in name):
|
|
||||||
suggestions.append(NUMERIC_SUGGESTION)
|
|
||||||
|
|
||||||
return suggestions
|
|
||||||
|
|
||||||
|
|
||||||
def is_name_taken(name: str) -> bool:
|
|
||||||
"""Check module filename for conflict.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name (str): Name of the project
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if name is taken, False otherwise
|
|
||||||
"""
|
|
||||||
response = _request_pypi(name)
|
|
||||||
|
|
||||||
if response:
|
|
||||||
package_url = response.get("info").get("package_url") # type: ignore
|
|
||||||
module_name = package_url.split("/")[-2]
|
|
||||||
return name.lower() == module_name.lower()
|
|
||||||
|
|
||||||
return False
|
|
@ -1,79 +0,0 @@
|
|||||||
# Contributing to ____project_name
|
|
||||||
|
|
||||||
Hi there! Thank you for even being interested in contributing to ____project_name.
|
|
||||||
|
|
||||||
## 🚀 Quick Start
|
|
||||||
|
|
||||||
To install requirements:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
poetry install -e ".[dev]"
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install all requirements for running the package, examples, linting, formatting, tests, and coverage.
|
|
||||||
|
|
||||||
Now, you should be able to run the common tasks in the following section. To double check, run `make test`, all tests should pass.
|
|
||||||
|
|
||||||
## ✅ Common Tasks
|
|
||||||
|
|
||||||
Type `make` for a list of common tasks.
|
|
||||||
|
|
||||||
### Code Formatting
|
|
||||||
|
|
||||||
Formatting for this project is done via a combination of [Black](https://black.readthedocs.io/en/stable/) and [isort](https://pycqa.github.io/isort/).
|
|
||||||
|
|
||||||
To run formatting for this project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make format
|
|
||||||
```
|
|
||||||
|
|
||||||
Additionally, you can run the formatter only on the files that have been modified in your current branch as compared to the main branch using the format_diff command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make format_diff
|
|
||||||
```
|
|
||||||
|
|
||||||
This is especially useful when you have made changes to a subset of the project and want to ensure your changes are properly formatted without affecting the rest of the codebase.
|
|
||||||
|
|
||||||
### Linting
|
|
||||||
|
|
||||||
Linting for this project is done via a combination of [Black](https://black.readthedocs.io/en/stable/), [isort](https://pycqa.github.io/isort/), [flake8](https://flake8.pycqa.org/en/latest/), and [mypy](http://mypy-lang.org/).
|
|
||||||
|
|
||||||
To run linting for this project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make lint
|
|
||||||
```
|
|
||||||
|
|
||||||
In addition, you can run the linter only on the files that have been modified in your current branch as compared to the main branch using the lint_diff command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make lint_diff
|
|
||||||
```
|
|
||||||
|
|
||||||
This can be very helpful when you've made changes to only certain parts of the project and want to ensure your changes meet the linting standards without having to check the entire codebase.
|
|
||||||
|
|
||||||
We recognize linting can be annoying - if you do not want to do it, please contact a project maintainer, and they can help you with it. We do not want this to be a blocker for good code getting contributed.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
To run unit tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make test
|
|
||||||
```
|
|
||||||
|
|
||||||
If you add new logic, please add a unit test.
|
|
||||||
|
|
||||||
## 🏭 Release Process
|
|
||||||
|
|
||||||
____project_name follows the [semver](https://semver.org/) versioning standard.
|
|
||||||
|
|
||||||
To use the [automated release workflow](./workflows/release.yml) you'll need to set up a PyPI account and [create an API token](https://pypi.org/help/#apitoken). Configure the API token for this GitHub repo by going to settings -> security -> secrets -> actions, creating the `PYPI_API_TOKEN` variable and setting the value to be your PyPI API token.
|
|
||||||
|
|
||||||
Once that's set up, you can release a new version of the package by opening a PR that:
|
|
||||||
1. updates the package version in the [pyproject.toml file](../pyproject.toml),
|
|
||||||
2. labels the PR with a `release` tag.
|
|
||||||
When the PR is merged into main, a new release will be created.
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY . /app
|
|
||||||
|
|
||||||
RUN pip install --no-cache-dir .
|
|
||||||
|
|
||||||
CMD exec uvicorn ____project_name_identifier.server:app --host 0.0.0.0 --port $PORT
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
|||||||
.PHONY: all format lint test help
|
|
||||||
|
|
||||||
# Default target executed when no arguments are given to make.
|
|
||||||
all: help
|
|
||||||
|
|
||||||
start:
|
|
||||||
uvicorn ____project_name_identifier.server:app --reload
|
|
||||||
|
|
||||||
# Define a variable for the test file path.
|
|
||||||
TEST_FILE ?= tests/
|
|
||||||
|
|
||||||
test:
|
|
||||||
pytest $(TEST_FILE)
|
|
||||||
|
|
||||||
# Define a variable for Python and notebook files.
|
|
||||||
PYTHON_FILES=.
|
|
||||||
lint format: PYTHON_FILES=.
|
|
||||||
lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --diff-filter=d main | grep -E '\.py$$|\.ipynb$$')
|
|
||||||
|
|
||||||
lint lint_diff:
|
|
||||||
mypy $(PYTHON_FILES)
|
|
||||||
black $(PYTHON_FILES) --check
|
|
||||||
ruff .
|
|
||||||
|
|
||||||
format format_diff:
|
|
||||||
black $(PYTHON_FILES)
|
|
||||||
ruff --select I --fix $(PYTHON_FILES)
|
|
||||||
|
|
||||||
deploy_gcp:
|
|
||||||
gcloud run deploy ____project_name_identifier --source . --port 8001 --env-vars-file .env.gcp.yaml --allow-unauthenticated --region us-central1 --min-instances 1
|
|
||||||
|
|
||||||
######################
|
|
||||||
# HELP
|
|
||||||
######################
|
|
||||||
|
|
||||||
help:
|
|
||||||
@echo '----'
|
|
||||||
@echo 'make start - start server'
|
|
||||||
@echo 'make format - run code formatters'
|
|
||||||
@echo 'make lint - run linters'
|
|
||||||
@echo 'make test - run unit tests'
|
|
||||||
@echo 'make deploy_gcp - deploy to GCP'
|
|
@ -1,52 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "____project_name"
|
|
||||||
version = "0.0.1"
|
|
||||||
description = ""
|
|
||||||
authors = [{name = "____author_name", email = "____author_email"}]
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.8,<4.0"
|
|
||||||
dependencies = [
|
|
||||||
"langchain~=____langchain_version",
|
|
||||||
"langserve[server]>=0.0.6",
|
|
||||||
"tiktoken~=0.4.0",
|
|
||||||
"openai~=0.27.8",
|
|
||||||
"fastapi~=0.96.0",
|
|
||||||
"uvicorn[standard]~=0.22.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools>=61.0"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project.optional-dependencies]
|
|
||||||
dev = [
|
|
||||||
"pytest~=7.4.0",
|
|
||||||
"pytest-asyncio~=0.21.1",
|
|
||||||
"mypy~=1.4.1",
|
|
||||||
"ruff~=0.0.278",
|
|
||||||
"black~=23.7.0",
|
|
||||||
"syrupy~=4.0.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.ruff]
|
|
||||||
select = [
|
|
||||||
"E", # pycodestyle
|
|
||||||
"F", # pyflakes
|
|
||||||
"I", # isort
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.mypy]
|
|
||||||
ignore_missing_imports = "True"
|
|
||||||
disallow_untyped_defs = "True"
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
# --strict-markers will raise errors on unknown marks.
|
|
||||||
# https://docs.pytest.org/en/7.1.x/how-to/mark.html#raising-errors-on-unknown-marks
|
|
||||||
#
|
|
||||||
# https://docs.pytest.org/en/7.1.x/reference/reference.html
|
|
||||||
# --strict-config any warnings encountered while parsing the `pytest`
|
|
||||||
# section of the configuration file raise errors.
|
|
||||||
#
|
|
||||||
# https://github.com/tophat/syrupy
|
|
||||||
# --snapshot-warn-unused Prints a warning on unused snapshots rather than fail the test suite.
|
|
||||||
addopts = "--strict-markers --strict-config --durations=5 --snapshot-warn-unused"
|
|
@ -1,89 +0,0 @@
|
|||||||
# Contributing to ____project_name
|
|
||||||
|
|
||||||
Hi there! Thank you for even being interested in contributing to ____project_name.
|
|
||||||
|
|
||||||
## 🚀 Quick Start
|
|
||||||
|
|
||||||
This project uses [Poetry](https://python-poetry.org/) as a dependency manager. Check out Poetry's [documentation on how to install it](https://python-poetry.org/docs/#installation) on your system before proceeding.
|
|
||||||
|
|
||||||
❗Note: If you use `Conda` or `Pyenv` as your environment / package manager, avoid dependency conflicts by doing the following first:
|
|
||||||
1. *Before installing Poetry*, create and activate a new Conda env (e.g. `conda create -n langchain python=3.9`)
|
|
||||||
2. Install Poetry (see above)
|
|
||||||
3. Tell Poetry to use the virtualenv python environment (`poetry config virtualenvs.prefer-active-python true`)
|
|
||||||
4. Continue with the following steps.
|
|
||||||
|
|
||||||
To install requirements:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
poetry install
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install all requirements for running the package, examples, linting, formatting, tests, and coverage.
|
|
||||||
|
|
||||||
❗Note: If you're running Poetry 1.4.1 and receive a `WheelFileValidationError` for `debugpy` during installation, you can try either downgrading to Poetry 1.4.0 or disabling "modern installation" (`poetry config installer.modern-installation false`) and re-install requirements. See [this `debugpy` issue](https://github.com/microsoft/debugpy/issues/1246) for more details.
|
|
||||||
|
|
||||||
Now, you should be able to run the common tasks in the following section.
|
|
||||||
|
|
||||||
## ✅ Common Tasks
|
|
||||||
|
|
||||||
Type `make` for a list of common tasks.
|
|
||||||
|
|
||||||
### Code Formatting
|
|
||||||
|
|
||||||
Formatting for this project is done via a combination of [Black](https://black.readthedocs.io/en/stable/) and [isort](https://pycqa.github.io/isort/).
|
|
||||||
|
|
||||||
To run formatting for this project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make format
|
|
||||||
```
|
|
||||||
|
|
||||||
Additionally, you can run the formatter only on the files that have been modified in your current branch as compared to the main branch using the format_diff command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make format_diff
|
|
||||||
```
|
|
||||||
|
|
||||||
This is especially useful when you have made changes to a subset of the project and want to ensure your changes are properly formatted without affecting the rest of the codebase.
|
|
||||||
|
|
||||||
### Linting
|
|
||||||
|
|
||||||
Linting for this project is done via a combination of [Black](https://black.readthedocs.io/en/stable/), [isort](https://pycqa.github.io/isort/), [flake8](https://flake8.pycqa.org/en/latest/), and [mypy](http://mypy-lang.org/).
|
|
||||||
|
|
||||||
To run linting for this project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make lint
|
|
||||||
```
|
|
||||||
|
|
||||||
In addition, you can run the linter only on the files that have been modified in your current branch as compared to the main branch using the lint_diff command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make lint_diff
|
|
||||||
```
|
|
||||||
|
|
||||||
This can be very helpful when you've made changes to only certain parts of the project and want to ensure your changes meet the linting standards without having to check the entire codebase.
|
|
||||||
|
|
||||||
We recognize linting can be annoying - if you do not want to do it, please contact a project maintainer, and they can help you with it. We do not want this to be a blocker for good code getting contributed.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
To run unit tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make test
|
|
||||||
```
|
|
||||||
|
|
||||||
If you add new logic, please add a unit test.
|
|
||||||
|
|
||||||
## 🏭 Release Process
|
|
||||||
|
|
||||||
____project_name follows the [semver](https://semver.org/) versioning standard.
|
|
||||||
|
|
||||||
To use the [automated release workflow](./workflows/release.yml) you'll need to set up a PyPI account and [create an API token](https://pypi.org/help/#apitoken). Configure the API token for this GitHub repo by going to settings -> security -> secrets -> actions, creating the `PYPI_API_TOKEN` variable and setting the value to be your PyPI API token.
|
|
||||||
|
|
||||||
Once that's set up, you can release a new version of the package by opening a PR that:
|
|
||||||
1. updates the package version in the [pyproject.toml file](../pyproject.toml),
|
|
||||||
2. labels the PR with a `release` tag.
|
|
||||||
When the PR is merged into main, a new release will be created.
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
|||||||
# An action for setting up poetry install with caching.
|
|
||||||
# Using a custom action since the default action does not
|
|
||||||
# take poetry install groups into account.
|
|
||||||
# Action code from:
|
|
||||||
# https://github.com/actions/setup-python/issues/505#issuecomment-1273013236
|
|
||||||
name: poetry-install-with-caching
|
|
||||||
description: Poetry install with support for caching of dependency groups.
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
python-version:
|
|
||||||
description: Python version, supporting MAJOR.MINOR only
|
|
||||||
required: true
|
|
||||||
|
|
||||||
poetry-version:
|
|
||||||
description: Poetry version
|
|
||||||
required: true
|
|
||||||
|
|
||||||
install-command:
|
|
||||||
description: Command run for installing dependencies
|
|
||||||
required: false
|
|
||||||
default: poetry install
|
|
||||||
|
|
||||||
cache-key:
|
|
||||||
description: Cache key to use for manual handling of caching
|
|
||||||
required: true
|
|
||||||
|
|
||||||
working-directory:
|
|
||||||
description: Directory to run install-command in
|
|
||||||
required: false
|
|
||||||
default: ""
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
name: Setup python $${ inputs.python-version }}
|
|
||||||
with:
|
|
||||||
python-version: ${{ inputs.python-version }}
|
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
id: cache-pip
|
|
||||||
name: Cache Pip ${{ inputs.python-version }}
|
|
||||||
env:
|
|
||||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "15"
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/pip
|
|
||||||
key: pip-${{ runner.os }}-${{ runner.arch }}-py-${{ inputs.python-version }}
|
|
||||||
|
|
||||||
- run: pipx install poetry==${{ inputs.poetry-version }} --python python${{ inputs.python-version }}
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Check Poetry File
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
poetry check
|
|
||||||
|
|
||||||
- name: Check lock file
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
poetry lock --check
|
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
id: cache-poetry
|
|
||||||
env:
|
|
||||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "15"
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/pypoetry/virtualenvs
|
|
||||||
~/.cache/pypoetry/cache
|
|
||||||
~/.cache/pypoetry/artifacts
|
|
||||||
key: poetry-${{ runner.os }}-${{ runner.arch }}-py-${{ inputs.python-version }}-poetry-${{ inputs.poetry-version }}-${{ hashFiles('poetry.lock') }}
|
|
||||||
|
|
||||||
- run: ${{ inputs.install-command }}
|
|
||||||
working-directory: ${{ inputs.working-directory }}
|
|
||||||
shell: bash
|
|
@ -1,36 +0,0 @@
|
|||||||
name: lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
env:
|
|
||||||
POETRY_VERSION: "1.4.2"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
python-version:
|
|
||||||
- "3.8"
|
|
||||||
- "3.9"
|
|
||||||
- "3.10"
|
|
||||||
- "3.11"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install poetry
|
|
||||||
run: |
|
|
||||||
pipx install poetry==$POETRY_VERSION
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
cache: poetry
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
poetry install
|
|
||||||
- name: Analysing the code with our lint
|
|
||||||
run: |
|
|
||||||
make lint
|
|
@ -1,49 +0,0 @@
|
|||||||
name: release
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- 'pyproject.toml'
|
|
||||||
|
|
||||||
env:
|
|
||||||
POETRY_VERSION: "1.4.2"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
if_release:
|
|
||||||
if: |
|
|
||||||
${{ github.event.pull_request.merged == true }}
|
|
||||||
&& ${{ contains(github.event.pull_request.labels.*.name, 'release') }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install poetry
|
|
||||||
run: pipx install poetry==$POETRY_VERSION
|
|
||||||
- name: Set up Python 3.10
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "3.10"
|
|
||||||
cache: "poetry"
|
|
||||||
- name: Build project for distribution
|
|
||||||
run: poetry build
|
|
||||||
- name: Check Version
|
|
||||||
id: check-version
|
|
||||||
run: |
|
|
||||||
echo version=$(poetry version --short) >> $GITHUB_OUTPUT
|
|
||||||
- name: Create Release
|
|
||||||
uses: ncipollo/release-action@v1
|
|
||||||
with:
|
|
||||||
artifacts: "dist/*"
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
draft: false
|
|
||||||
generateReleaseNotes: true
|
|
||||||
tag: v${{ steps.check-version.outputs.version }}
|
|
||||||
commit: master
|
|
||||||
- name: Publish to PyPI
|
|
||||||
env:
|
|
||||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
|
||||||
run: |
|
|
||||||
poetry publish
|
|
@ -1,36 +0,0 @@
|
|||||||
name: test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
POETRY_VERSION: "1.4.2"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
python-version:
|
|
||||||
- "3.8"
|
|
||||||
- "3.9"
|
|
||||||
- "3.10"
|
|
||||||
- "3.11"
|
|
||||||
name: Python ${{ matrix.python-version }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
|
||||||
uses: "./.github/actions/poetry_setup"
|
|
||||||
with:
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
poetry-version: "1.4.2"
|
|
||||||
install-command: |
|
|
||||||
echo "Running tests, installing dependencies with poetry..."
|
|
||||||
poetry install
|
|
||||||
- name: Run tests
|
|
||||||
run: |
|
|
||||||
make test
|
|
||||||
shell: bash
|
|
@ -1,11 +0,0 @@
|
|||||||
FROM python:3.11-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY . /app
|
|
||||||
|
|
||||||
RUN pip install poetry && \
|
|
||||||
poetry config virtualenvs.create false && \
|
|
||||||
poetry install --no-interaction --no-ansi --only main
|
|
||||||
|
|
||||||
CMD exec uvicorn ____project_name_identifier.server:app --host 0.0.0.0 --port $PORT
|
|
@ -1,42 +0,0 @@
|
|||||||
.PHONY: all format lint test help
|
|
||||||
|
|
||||||
# Default target executed when no arguments are given to make.
|
|
||||||
all: help
|
|
||||||
|
|
||||||
start:
|
|
||||||
poetry run uvicorn ____project_name_identifier.server:app --reload
|
|
||||||
|
|
||||||
# Define a variable for the test file path.
|
|
||||||
TEST_FILE ?= tests/
|
|
||||||
|
|
||||||
test:
|
|
||||||
poetry run pytest $(TEST_FILE)
|
|
||||||
|
|
||||||
# Define a variable for Python and notebook files.
|
|
||||||
PYTHON_FILES=.
|
|
||||||
lint format: PYTHON_FILES=.
|
|
||||||
lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --diff-filter=d main | grep -E '\.py$$|\.ipynb$$')
|
|
||||||
|
|
||||||
lint lint_diff:
|
|
||||||
poetry run mypy $(PYTHON_FILES)
|
|
||||||
poetry run black $(PYTHON_FILES) --check
|
|
||||||
poetry run ruff .
|
|
||||||
|
|
||||||
format format_diff:
|
|
||||||
poetry run black $(PYTHON_FILES)
|
|
||||||
poetry run ruff --select I --fix $(PYTHON_FILES)
|
|
||||||
|
|
||||||
deploy_gcp:
|
|
||||||
gcloud run deploy ____project_name_identifier --source . --port 8001 --env-vars-file .env.gcp.yaml --allow-unauthenticated --region us-central1 --min-instances 1
|
|
||||||
|
|
||||||
######################
|
|
||||||
# HELP
|
|
||||||
######################
|
|
||||||
|
|
||||||
help:
|
|
||||||
@echo '----'
|
|
||||||
@echo 'make start - start server'
|
|
||||||
@echo 'make format - run code formatters'
|
|
||||||
@echo 'make lint - run linters'
|
|
||||||
@echo 'make test - run unit tests'
|
|
||||||
@echo 'make deploy_gcp - deploy to GCP'
|
|
@ -1,2 +0,0 @@
|
|||||||
[virtualenvs]
|
|
||||||
in-project = true
|
|
@ -1,52 +0,0 @@
|
|||||||
[tool.poetry]
|
|
||||||
name = "____project_name"
|
|
||||||
version = "0.0.1"
|
|
||||||
description = ""
|
|
||||||
authors = ["____author_name <____author_email>"]
|
|
||||||
license = "MIT"
|
|
||||||
readme = "README.md"
|
|
||||||
packages = [{include = "____project_name_identifier"}]
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = "^3.8.1"
|
|
||||||
langchain = "^____langchain_version"
|
|
||||||
langserve = { version = ">=0.0.6", extras = ["server"] }
|
|
||||||
tiktoken = "^0.4.0"
|
|
||||||
openai = "^0.27.8"
|
|
||||||
fastapi = "^0.96.0"
|
|
||||||
uvicorn = {extras = ["standard"], version = "^0.22.0"}
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
pytest = "^7.4.0"
|
|
||||||
pytest-asyncio = "^0.21.1"
|
|
||||||
mypy = "^1.4.1"
|
|
||||||
ruff = "^0.0.278"
|
|
||||||
black = "^23.7.0"
|
|
||||||
syrupy = "^4.0.2"
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["poetry-core"]
|
|
||||||
build-backend = "poetry.core.masonry.api"
|
|
||||||
|
|
||||||
[tool.ruff]
|
|
||||||
select = [
|
|
||||||
"E", # pycodestyle
|
|
||||||
"F", # pyflakes
|
|
||||||
"I", # isort
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.mypy]
|
|
||||||
ignore_missing_imports = "True"
|
|
||||||
disallow_untyped_defs = "True"
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
# --strict-markers will raise errors on unknown marks.
|
|
||||||
# https://docs.pytest.org/en/7.1.x/how-to/mark.html#raising-errors-on-unknown-marks
|
|
||||||
#
|
|
||||||
# https://docs.pytest.org/en/7.1.x/reference/reference.html
|
|
||||||
# --strict-config any warnings encountered while parsing the `pytest`
|
|
||||||
# section of the configuration file raise errors.
|
|
||||||
#
|
|
||||||
# https://github.com/tophat/syrupy
|
|
||||||
# --snapshot-warn-unused Prints a warning on unused snapshots rather than fail the test suite.
|
|
||||||
addopts = "--strict-markers --strict-config --durations=5 --snapshot-warn-unused"
|
|
@ -1,2 +0,0 @@
|
|||||||
PORT=8001
|
|
||||||
OPENAI_API_KEY="your_secret_key_here"
|
|
@ -1 +0,0 @@
|
|||||||
OPENAI_API_KEY: your_secret_key_here
|
|
@ -1,158 +0,0 @@
|
|||||||
.vs/
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
docs/docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
notebooks/
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.envrc
|
|
||||||
.venv
|
|
||||||
.venvs
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
.env.gcp.yaml
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# macOS display setting files
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Wandb directory
|
|
||||||
wandb/
|
|
||||||
|
|
||||||
# asdf tool versions
|
|
||||||
.tool-versions
|
|
||||||
/.ruff_cache/
|
|
||||||
|
|
||||||
*.pkl
|
|
||||||
*.bin
|
|
||||||
|
|
||||||
# integration test artifacts
|
|
||||||
data_map*
|
|
||||||
\[('_type', 'fake'), ('stop', None)]
|
|
||||||
|
|
||||||
# Replit files
|
|
||||||
*replit*
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) ____author_name
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
@ -1,72 +0,0 @@
|
|||||||
# ____project_name
|
|
||||||
|
|
||||||
<!--- This is a LangChain project bootstrapped by [LangChain CLI](https://github.com/langchain-ai/langchain). --->
|
|
||||||
|
|
||||||
## Customise
|
|
||||||
|
|
||||||
To customise this project, edit the following files:
|
|
||||||
|
|
||||||
- `____project_name_identifier/chain.py` contains an example chain, which you can edit to suit your needs.
|
|
||||||
- `____project_name_identifier/server.py` contains a FastAPI app that serves that chain using `langserve`. You can edit this to add more endpoints or customise your server.
|
|
||||||
- `tests/test_chain.py` contains tests for the chain. You can edit this to add more tests.
|
|
||||||
- `pyproject.toml` contains the project metadata, including the project name, version, and dependencies. You can edit this to add more dependencies or customise your project metadata.
|
|
||||||
|
|
||||||
## Install dependencies
|
|
||||||
|
|
||||||
If using poetry:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
poetry install
|
|
||||||
```
|
|
||||||
|
|
||||||
If using vanilla pip:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
To run the project locally, run
|
|
||||||
|
|
||||||
```
|
|
||||||
make start
|
|
||||||
```
|
|
||||||
|
|
||||||
This will launch a webserver on port 8001.
|
|
||||||
|
|
||||||
Or via docker compose (does not use hot reload by default):
|
|
||||||
|
|
||||||
```
|
|
||||||
docker compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deploy
|
|
||||||
|
|
||||||
To deploy the project, first build the docker image:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker build . -t ____project_name_identifier:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run the image:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -p 8001:8001 -e PORT=8001 ____project_name_identifier:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
Don't forget to add any needed environment variables!
|
|
||||||
|
|
||||||
## Deploy to GCP
|
|
||||||
|
|
||||||
You can deploy to GCP Cloud Run using the following command:
|
|
||||||
|
|
||||||
First edit `.env.gcp.yaml` file with any environment variables you need. Then run:
|
|
||||||
|
|
||||||
```
|
|
||||||
make deploy_gcp
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
For information on how to set up your dev environment and contribute, see [here](.github/CONTRIBUTING.md).
|
|
@ -1,12 +0,0 @@
|
|||||||
"""____project_name_identifier package."""
|
|
||||||
from importlib import metadata
|
|
||||||
|
|
||||||
from ____project_name_identifier.chain import get_chain
|
|
||||||
|
|
||||||
try:
|
|
||||||
__version__ = metadata.version(__package__)
|
|
||||||
except metadata.PackageNotFoundError:
|
|
||||||
# Case where package metadata is not available.
|
|
||||||
__version__ = ""
|
|
||||||
|
|
||||||
__all__ = [__version__, "get_chain"]
|
|
@ -1,29 +0,0 @@
|
|||||||
"""This is a template for a custom chain.
|
|
||||||
|
|
||||||
Edit this file to implement your chain logic.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from langchain.chat_models.openai import ChatOpenAI
|
|
||||||
from langchain.output_parsers.list import CommaSeparatedListOutputParser
|
|
||||||
from langchain.prompts.chat import ChatPromptTemplate
|
|
||||||
from langchain.schema.language_model import BaseLanguageModel
|
|
||||||
from langchain.schema.runnable import Runnable
|
|
||||||
|
|
||||||
template = """You are a helpful assistant who generates comma separated lists.
|
|
||||||
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
|
|
||||||
ONLY return a comma separated list, and nothing more.""" # noqa: E501
|
|
||||||
human_template = "{text}"
|
|
||||||
|
|
||||||
|
|
||||||
def get_chain(model: Optional[BaseLanguageModel] = None) -> Runnable:
|
|
||||||
"""Return a chain."""
|
|
||||||
model = model or ChatOpenAI()
|
|
||||||
prompt = ChatPromptTemplate.from_messages(
|
|
||||||
[
|
|
||||||
("system", template),
|
|
||||||
("human", human_template),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return prompt | model | CommaSeparatedListOutputParser()
|
|
@ -1,17 +0,0 @@
|
|||||||
from fastapi import FastAPI
|
|
||||||
from langserve import add_routes
|
|
||||||
|
|
||||||
from ____project_name_identifier.chain import get_chain
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
add_routes(
|
|
||||||
app,
|
|
||||||
get_chain(),
|
|
||||||
config_keys=["tags"],
|
|
||||||
)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import uvicorn
|
|
||||||
|
|
||||||
uvicorn.run(app, host="0.0.0.0", port=8001)
|
|
@ -1,12 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
server:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
image: ____project_name:latest
|
|
||||||
container_name: ____project_name
|
|
||||||
ports:
|
|
||||||
- "8001:8001"
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
@ -1,10 +0,0 @@
|
|||||||
from ____project_name_identifier import get_chain
|
|
||||||
|
|
||||||
|
|
||||||
def test_my_chain() -> None:
|
|
||||||
"""Edit this test to test your chain."""
|
|
||||||
from langchain.llms.human import HumanInputLLM
|
|
||||||
|
|
||||||
llm = HumanInputLLM(input_func=lambda *args, **kwargs: "foo")
|
|
||||||
chain = get_chain(llm)
|
|
||||||
chain.invoke({"text": "foo"})
|
|
@ -1,29 +0,0 @@
|
|||||||
"""Look up user information from local git."""
|
|
||||||
import subprocess
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
def get_git_user_name() -> Optional[str]:
|
|
||||||
"""Get the user's name from git, if it is configured, otherwise None."""
|
|
||||||
try:
|
|
||||||
return (
|
|
||||||
subprocess.run(["git", "config", "--get", "user.name"], capture_output=True)
|
|
||||||
.stdout.decode()
|
|
||||||
.strip()
|
|
||||||
)
|
|
||||||
except FileNotFoundError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_git_user_email() -> Optional[str]:
|
|
||||||
"""Get the user's email from git if it is configured, otherwise None."""
|
|
||||||
try:
|
|
||||||
return (
|
|
||||||
subprocess.run(
|
|
||||||
["git", "config", "--get", "user.email"], capture_output=True
|
|
||||||
)
|
|
||||||
.stdout.decode()
|
|
||||||
.strip()
|
|
||||||
)
|
|
||||||
except FileNotFoundError:
|
|
||||||
return None
|
|
Loading…
Reference in New Issue