diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4d86dac6a59cf..8d776064019a7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,19 +1,24 @@ Thank you for contributing to LangChain! -Checklist: - -- [ ] PR title: Please title your PR "package: description", where "package" is whichever of langchain, community, core, experimental, etc. is being modified. Use "docs: ..." for purely docs changes, "templates: ..." for template changes, "infra: ..." for CI changes. +- [ ] **PR title**: "package: description" + - Where "package" is whichever of langchain, community, core, experimental, etc. is being modified. Use "docs: ..." for purely docs changes, "templates: ..." for template changes, "infra: ..." for CI changes. - Example: "community: add foobar LLM" -- [ ] PR message: **Delete this entire template message** and replace it with the following bulleted list + + +- [ ] **PR message**: ***Delete this entire checklist*** and replace with - **Description:** a description of the change - **Issue:** the issue # it fixes, if applicable - **Dependencies:** any dependencies required for this change - **Twitter handle:** if your PR gets announced, and you'd like a mention, we'll gladly shout you out! -- [ ] Pass lint and test: Run `make format`, `make lint` and `make test` from the root of the package(s) you've modified to check that you're passing lint and testing. See contribution guidelines for more information on how to write/run tests, lint, etc: https://python.langchain.com/docs/contributing/ -- [ ] Add tests and docs: If you're adding a new integration, please include + + +- [ ] **Add tests and docs**: 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/docs/integrations` directory. + +- [ ] **Lint and test**: Run `make format`, `make lint` and `make test` from the root of the package(s) you've modified. See contribution guidelines for more: https://python.langchain.com/docs/contributing/ + Additional guidelines: - Make sure optional dependencies are imported within a function. - Please do not add dependencies to pyproject.toml files (even optional ones) unless they are required for unit tests. diff --git a/.github/actions/people/Dockerfile b/.github/actions/people/Dockerfile new file mode 100644 index 0000000000000..bf214eea7dcc3 --- /dev/null +++ b/.github/actions/people/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.9 + +RUN pip install httpx PyGithub "pydantic==2.0.2" pydantic-settings "pyyaml>=5.3.1,<6.0.0" + +COPY ./app /app + +CMD ["python", "/app/main.py"] \ No newline at end of file diff --git a/.github/actions/people/action.yml b/.github/actions/people/action.yml new file mode 100644 index 0000000000000..15a00c108b472 --- /dev/null +++ b/.github/actions/people/action.yml @@ -0,0 +1,11 @@ +# Adapted from https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/action.yml +name: "Generate LangChain People" +description: "Generate the data for the LangChain People page" +author: "Jacob Lee " +inputs: + token: + description: 'User token, to read the GitHub API. Can be passed in using {{ secrets.LANGCHAIN_PEOPLE_GITHUB_TOKEN }}' + required: true +runs: + using: 'docker' + image: 'Dockerfile' \ No newline at end of file diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py new file mode 100644 index 0000000000000..98a331450bf8a --- /dev/null +++ b/.github/actions/people/app/main.py @@ -0,0 +1,632 @@ +# Adapted from https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py + +import logging +import subprocess +import sys +from collections import Counter +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any, Container, Dict, List, Set, Union + +import httpx +import yaml +from github import Github +from pydantic import BaseModel, SecretStr +from pydantic_settings import BaseSettings + +github_graphql_url = "https://api.github.com/graphql" +questions_category_id = "DIC_kwDOIPDwls4CS6Ve" + +# discussions_query = """ +# query Q($after: String, $category_id: ID) { +# repository(name: "langchain", owner: "langchain-ai") { +# discussions(first: 100, after: $after, categoryId: $category_id) { +# edges { +# cursor +# node { +# number +# author { +# login +# avatarUrl +# url +# } +# title +# createdAt +# comments(first: 100) { +# nodes { +# createdAt +# author { +# login +# avatarUrl +# url +# } +# isAnswer +# replies(first: 10) { +# nodes { +# createdAt +# author { +# login +# avatarUrl +# url +# } +# } +# } +# } +# } +# } +# } +# } +# } +# } +# """ + +# issues_query = """ +# query Q($after: String) { +# repository(name: "langchain", owner: "langchain-ai") { +# issues(first: 100, after: $after) { +# edges { +# cursor +# node { +# number +# author { +# login +# avatarUrl +# url +# } +# title +# createdAt +# state +# comments(first: 100) { +# nodes { +# createdAt +# author { +# login +# avatarUrl +# url +# } +# } +# } +# } +# } +# } +# } +# } +# """ + +prs_query = """ +query Q($after: String) { + repository(name: "langchain", owner: "langchain-ai") { + pullRequests(first: 100, after: $after, states: MERGED) { + edges { + cursor + node { + changedFiles + additions + deletions + number + labels(first: 100) { + nodes { + name + } + } + author { + login + avatarUrl + url + } + title + createdAt + state + reviews(first:100) { + nodes { + author { + login + avatarUrl + url + } + state + } + } + } + } + } + } +} +""" + + +class Author(BaseModel): + login: str + avatarUrl: str + url: str + + +# Issues and Discussions + + +class CommentsNode(BaseModel): + createdAt: datetime + author: Union[Author, None] = None + + +class Replies(BaseModel): + nodes: List[CommentsNode] + + +class DiscussionsCommentsNode(CommentsNode): + replies: Replies + + +class Comments(BaseModel): + nodes: List[CommentsNode] + + +class DiscussionsComments(BaseModel): + nodes: List[DiscussionsCommentsNode] + + +class IssuesNode(BaseModel): + number: int + author: Union[Author, None] = None + title: str + createdAt: datetime + state: str + comments: Comments + + +class DiscussionsNode(BaseModel): + number: int + author: Union[Author, None] = None + title: str + createdAt: datetime + comments: DiscussionsComments + + +class IssuesEdge(BaseModel): + cursor: str + node: IssuesNode + + +class DiscussionsEdge(BaseModel): + cursor: str + node: DiscussionsNode + + +class Issues(BaseModel): + edges: List[IssuesEdge] + + +class Discussions(BaseModel): + edges: List[DiscussionsEdge] + + +class IssuesRepository(BaseModel): + issues: Issues + + +class DiscussionsRepository(BaseModel): + discussions: Discussions + + +class IssuesResponseData(BaseModel): + repository: IssuesRepository + + +class DiscussionsResponseData(BaseModel): + repository: DiscussionsRepository + + +class IssuesResponse(BaseModel): + data: IssuesResponseData + + +class DiscussionsResponse(BaseModel): + data: DiscussionsResponseData + + +# PRs + + +class LabelNode(BaseModel): + name: str + + +class Labels(BaseModel): + nodes: List[LabelNode] + + +class ReviewNode(BaseModel): + author: Union[Author, None] = None + state: str + + +class Reviews(BaseModel): + nodes: List[ReviewNode] + + +class PullRequestNode(BaseModel): + number: int + labels: Labels + author: Union[Author, None] = None + changedFiles: int + additions: int + deletions: int + title: str + createdAt: datetime + state: str + reviews: Reviews + # comments: Comments + + +class PullRequestEdge(BaseModel): + cursor: str + node: PullRequestNode + + +class PullRequests(BaseModel): + edges: List[PullRequestEdge] + + +class PRsRepository(BaseModel): + pullRequests: PullRequests + + +class PRsResponseData(BaseModel): + repository: PRsRepository + + +class PRsResponse(BaseModel): + data: PRsResponseData + + +class Settings(BaseSettings): + input_token: SecretStr + github_repository: str + httpx_timeout: int = 30 + + +def get_graphql_response( + *, + settings: Settings, + query: str, + after: Union[str, None] = None, + category_id: Union[str, None] = None, +) -> Dict[str, Any]: + headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"} + # category_id is only used by one query, but GraphQL allows unused variables, so + # keep it here for simplicity + variables = {"after": after, "category_id": category_id} + response = httpx.post( + github_graphql_url, + headers=headers, + timeout=settings.httpx_timeout, + json={"query": query, "variables": variables, "operationName": "Q"}, + ) + if response.status_code != 200: + logging.error( + f"Response was not 200, after: {after}, category_id: {category_id}" + ) + logging.error(response.text) + raise RuntimeError(response.text) + data = response.json() + if "errors" in data: + logging.error(f"Errors in response, after: {after}, category_id: {category_id}") + logging.error(data["errors"]) + logging.error(response.text) + raise RuntimeError(response.text) + return data + + +# def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None): +# data = get_graphql_response(settings=settings, query=issues_query, after=after) +# graphql_response = IssuesResponse.model_validate(data) +# return graphql_response.data.repository.issues.edges + + +# def get_graphql_question_discussion_edges( +# *, +# settings: Settings, +# after: Union[str, None] = None, +# ): +# data = get_graphql_response( +# settings=settings, +# query=discussions_query, +# after=after, +# category_id=questions_category_id, +# ) +# graphql_response = DiscussionsResponse.model_validate(data) +# return graphql_response.data.repository.discussions.edges + + +def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None): + if after is None: + print("Querying PRs...") + else: + print(f"Querying PRs with cursor {after}...") + data = get_graphql_response( + settings=settings, + query=prs_query, + after=after + ) + graphql_response = PRsResponse.model_validate(data) + return graphql_response.data.repository.pullRequests.edges + + +# def get_issues_experts(settings: Settings): +# issue_nodes: List[IssuesNode] = [] +# issue_edges = get_graphql_issue_edges(settings=settings) + +# while issue_edges: +# for edge in issue_edges: +# issue_nodes.append(edge.node) +# last_edge = issue_edges[-1] +# issue_edges = get_graphql_issue_edges(settings=settings, after=last_edge.cursor) + +# commentors = Counter() +# last_month_commentors = Counter() +# authors: Dict[str, Author] = {} + +# now = datetime.now(tz=timezone.utc) +# one_month_ago = now - timedelta(days=30) + +# for issue in issue_nodes: +# issue_author_name = None +# if issue.author: +# authors[issue.author.login] = issue.author +# issue_author_name = issue.author.login +# issue_commentors = set() +# for comment in issue.comments.nodes: +# if comment.author: +# authors[comment.author.login] = comment.author +# if comment.author.login != issue_author_name: +# issue_commentors.add(comment.author.login) +# for author_name in issue_commentors: +# commentors[author_name] += 1 +# if issue.createdAt > one_month_ago: +# last_month_commentors[author_name] += 1 + +# return commentors, last_month_commentors, authors + + +# def get_discussions_experts(settings: Settings): +# discussion_nodes: List[DiscussionsNode] = [] +# discussion_edges = get_graphql_question_discussion_edges(settings=settings) + +# while discussion_edges: +# for discussion_edge in discussion_edges: +# discussion_nodes.append(discussion_edge.node) +# last_edge = discussion_edges[-1] +# discussion_edges = get_graphql_question_discussion_edges( +# settings=settings, after=last_edge.cursor +# ) + +# commentors = Counter() +# last_month_commentors = Counter() +# authors: Dict[str, Author] = {} + +# now = datetime.now(tz=timezone.utc) +# one_month_ago = now - timedelta(days=30) + +# for discussion in discussion_nodes: +# discussion_author_name = None +# if discussion.author: +# authors[discussion.author.login] = discussion.author +# discussion_author_name = discussion.author.login +# discussion_commentors = set() +# for comment in discussion.comments.nodes: +# if comment.author: +# authors[comment.author.login] = comment.author +# if comment.author.login != discussion_author_name: +# discussion_commentors.add(comment.author.login) +# for reply in comment.replies.nodes: +# if reply.author: +# authors[reply.author.login] = reply.author +# if reply.author.login != discussion_author_name: +# discussion_commentors.add(reply.author.login) +# for author_name in discussion_commentors: +# commentors[author_name] += 1 +# if discussion.createdAt > one_month_ago: +# last_month_commentors[author_name] += 1 +# return commentors, last_month_commentors, authors + + +# def get_experts(settings: Settings): +# ( +# discussions_commentors, +# discussions_last_month_commentors, +# discussions_authors, +# ) = get_discussions_experts(settings=settings) +# commentors = discussions_commentors +# last_month_commentors = discussions_last_month_commentors +# authors = {**discussions_authors} +# return commentors, last_month_commentors, authors + + +def _logistic(x, k): + return x / (x + k) + + +def get_contributors(settings: Settings): + pr_nodes: List[PullRequestNode] = [] + pr_edges = get_graphql_pr_edges(settings=settings) + + while pr_edges: + for edge in pr_edges: + pr_nodes.append(edge.node) + last_edge = pr_edges[-1] + pr_edges = get_graphql_pr_edges(settings=settings, after=last_edge.cursor) + + contributors = Counter() + contributor_scores = Counter() + recent_contributor_scores = Counter() + reviewers = Counter() + authors: Dict[str, Author] = {} + + for pr in pr_nodes: + pr_reviewers: Set[str] = set() + for review in pr.reviews.nodes: + if review.author: + authors[review.author.login] = review.author + pr_reviewers.add(review.author.login) + for reviewer in pr_reviewers: + reviewers[reviewer] += 1 + if pr.author: + authors[pr.author.login] = pr.author + contributors[pr.author.login] += 1 + files_changed = pr.changedFiles + lines_changed = pr.additions + pr.deletions + score = _logistic(files_changed, 20) + _logistic(lines_changed, 100) + contributor_scores[pr.author.login] += score + three_months_ago = (datetime.now(timezone.utc) - timedelta(days=3*30)) + if pr.createdAt > three_months_ago: + recent_contributor_scores[pr.author.login] += score + return contributors, contributor_scores, recent_contributor_scores, reviewers, authors + + +def get_top_users( + *, + counter: Counter, + min_count: int, + authors: Dict[str, Author], + skip_users: Container[str], +): + users = [] + for commentor, count in counter.most_common(): + if commentor in skip_users: + continue + if count >= min_count: + author = authors[commentor] + users.append( + { + "login": commentor, + "count": count, + "avatarUrl": author.avatarUrl, + "url": author.url, + } + ) + return users + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + settings = Settings() + logging.info(f"Using config: {settings.model_dump_json()}") + g = Github(settings.input_token.get_secret_value()) + repo = g.get_repo(settings.github_repository) + # question_commentors, question_last_month_commentors, question_authors = get_experts( + # settings=settings + # ) + contributors, contributor_scores, recent_contributor_scores, reviewers, pr_authors = get_contributors( + settings=settings + ) + # authors = {**question_authors, **pr_authors} + authors = {**pr_authors} + maintainers_logins = { + "hwchase17", + "agola11", + "baskaryan", + "hinthornw", + "nfcampos", + "efriis", + "eyurtsev", + "rlancemartin" + } + hidden_logins = { + "dev2049", + "vowelparrot", + "obi1kenobi", + "langchain-infra", + "jacoblee93", + "dqbd", + "bracesproul", + "akira", + } + bot_names = {"dosubot", "github-actions", "CodiumAI-Agent"} + maintainers = [] + for login in maintainers_logins: + user = authors[login] + maintainers.append( + { + "login": login, + "count": contributors[login], #+ question_commentors[login], + "avatarUrl": user.avatarUrl, + "url": user.url, + } + ) + + # min_count_expert = 10 + # min_count_last_month = 3 + min_score_contributor = 1 + min_count_reviewer = 5 + skip_users = maintainers_logins | bot_names | hidden_logins + # experts = get_top_users( + # counter=question_commentors, + # min_count=min_count_expert, + # authors=authors, + # skip_users=skip_users, + # ) + # last_month_active = get_top_users( + # counter=question_last_month_commentors, + # min_count=min_count_last_month, + # authors=authors, + # skip_users=skip_users, + # ) + top_recent_contributors = get_top_users( + counter=recent_contributor_scores, + min_count=min_score_contributor, + authors=authors, + skip_users=skip_users, + ) + top_contributors = get_top_users( + counter=contributor_scores, + min_count=min_score_contributor, + authors=authors, + skip_users=skip_users, + ) + top_reviewers = get_top_users( + counter=reviewers, + min_count=min_count_reviewer, + authors=authors, + skip_users=skip_users, + ) + + people = { + "maintainers": maintainers, + # "experts": experts, + # "last_month_active": last_month_active, + "top_recent_contributors": top_recent_contributors, + "top_contributors": top_contributors, + "top_reviewers": top_reviewers, + } + people_path = Path("./docs/data/people.yml") + people_old_content = people_path.read_text(encoding="utf-8") + new_people_content = yaml.dump( + people, sort_keys=False, width=200, allow_unicode=True + ) + if ( + people_old_content == new_people_content + ): + logging.info("The LangChain People data hasn't changed, finishing.") + sys.exit(0) + people_path.write_text(new_people_content, encoding="utf-8") + logging.info("Setting up GitHub Actions git user") + subprocess.run(["git", "config", "user.name", "github-actions"], check=True) + subprocess.run( + ["git", "config", "user.email", "github-actions@github.com"], check=True + ) + branch_name = "langchain/langchain-people" + logging.info(f"Creating a new branch {branch_name}") + subprocess.run(["git", "checkout", "-B", branch_name], check=True) + logging.info("Adding updated file") + subprocess.run( + ["git", "add", str(people_path)], check=True + ) + logging.info("Committing updated file") + message = "👥 Update LangChain people data" + result = subprocess.run(["git", "commit", "-m", message], check=True) + logging.info("Pushing branch") + subprocess.run(["git", "push", "origin", branch_name, "-f"], check=True) + logging.info("Creating PR") + pr = repo.create_pull(title=message, body=message, base="master", head=branch_name) + logging.info(f"Created PR: {pr.number}") + logging.info("Finished") \ No newline at end of file diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml new file mode 100644 index 0000000000000..e176dd691717e --- /dev/null +++ b/.github/workflows/people.yml @@ -0,0 +1,36 @@ +name: LangChain People + +on: + schedule: + - cron: "0 14 1 * *" + push: + branches: [jacob/people] + workflow_dispatch: + inputs: + debug_enabled: + description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + required: false + default: 'false' + +jobs: + langchain-people: + if: github.repository_owner == 'langchain-ai' + runs-on: ubuntu-latest + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + - uses: actions/checkout@v4 + # Ref: https://github.com/actions/runner/issues/2033 + - name: Fix git safe.directory in container + run: mkdir -p /home/runner/work/_temp/_github_home && printf "[safe]\n\tdirectory = /github/workspace" > /home/runner/work/_temp/_github_home/.gitconfig + # Allow debugging with tmate + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} + with: + limit-access-to-actor: true + - uses: ./.github/actions/people + with: + token: ${{ secrets.LANGCHAIN_PEOPLE_GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 407a65571adcd..db21b911098a8 100644 --- a/.gitignore +++ b/.gitignore @@ -177,4 +177,6 @@ docs/docs/build docs/docs/node_modules docs/docs/yarn.lock _dist -docs/docs/templates \ No newline at end of file +docs/docs/templates + +prof diff --git a/cookbook/amazon_personalize_how_to.ipynb b/cookbook/amazon_personalize_how_to.ipynb new file mode 100644 index 0000000000000..7555e39d89494 --- /dev/null +++ b/cookbook/amazon_personalize_how_to.ipynb @@ -0,0 +1,284 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Amazon Personalize\n", + "\n", + "[Amazon Personalize](https://docs.aws.amazon.com/personalize/latest/dg/what-is-personalize.html) is a fully managed machine learning service that uses your data to generate item recommendations for your users. It can also generate user segments based on the users' affinity for certain items or item metadata.\n", + "\n", + "This notebook goes through how to use Amazon Personalize Chain. You need a Amazon Personalize campaign_arn or a recommender_arn before you get started with the below notebook.\n", + "\n", + "Following is a [tutorial](https://github.com/aws-samples/retail-demo-store/blob/master/workshop/1-Personalization/Lab-1-Introduction-and-data-preparation.ipynb) to setup a campaign_arn/recommender_arn on Amazon Personalize. Once the campaign_arn/recommender_arn is setup, you can use it in the langchain ecosystem. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Install Dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "!pip install boto3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Sample Use-cases" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.1 [Use-case-1] Setup Amazon Personalize Client and retrieve recommendations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_experimental.recommenders import AmazonPersonalize\n", + "\n", + "recommender_arn = \"\"\n", + "\n", + "client = AmazonPersonalize(\n", + " credentials_profile_name=\"default\",\n", + " region_name=\"us-west-2\",\n", + " recommender_arn=recommender_arn,\n", + ")\n", + "client.get_recommendations(user_id=\"1\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "### 2.2 [Use-case-2] Invoke Personalize Chain for summarizing results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "from langchain.llms.bedrock import Bedrock\n", + "from langchain_experimental.recommenders import AmazonPersonalizeChain\n", + "\n", + "bedrock_llm = Bedrock(model_id=\"anthropic.claude-v2\", region_name=\"us-west-2\")\n", + "\n", + "# Create personalize chain\n", + "# Use return_direct=True if you do not want summary\n", + "chain = AmazonPersonalizeChain.from_llm(\n", + " llm=bedrock_llm, client=client, return_direct=False\n", + ")\n", + "response = chain({\"user_id\": \"1\"})\n", + "print(response)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3 [Use-Case-3] Invoke Amazon Personalize Chain using your own prompt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.prompts.prompt import PromptTemplate\n", + "\n", + "RANDOM_PROMPT_QUERY = \"\"\"\n", + "You are a skilled publicist. Write a high-converting marketing email advertising several movies available in a video-on-demand streaming platform next week, \n", + " given the movie and user information below. Your email will leverage the power of storytelling and persuasive language. \n", + " The movies to recommend and their information is contained in the tag. \n", + " All movies in the tag must be recommended. Give a summary of the movies and why the human should watch them. \n", + " Put the email between tags.\n", + "\n", + " \n", + " {result} \n", + " \n", + "\n", + " Assistant:\n", + " \"\"\"\n", + "\n", + "RANDOM_PROMPT = PromptTemplate(input_variables=[\"result\"], template=RANDOM_PROMPT_QUERY)\n", + "\n", + "chain = AmazonPersonalizeChain.from_llm(\n", + " llm=bedrock_llm, client=client, return_direct=False, prompt_template=RANDOM_PROMPT\n", + ")\n", + "chain.run({\"user_id\": \"1\", \"item_id\": \"234\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.4 [Use-case-4] Invoke Amazon Personalize in a Sequential Chain " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.chains import LLMChain, SequentialChain\n", + "\n", + "RANDOM_PROMPT_QUERY_2 = \"\"\"\n", + "You are a skilled publicist. Write a high-converting marketing email advertising several movies available in a video-on-demand streaming platform next week, \n", + " given the movie and user information below. Your email will leverage the power of storytelling and persuasive language. \n", + " You want the email to impress the user, so make it appealing to them.\n", + " The movies to recommend and their information is contained in the tag. \n", + " All movies in the tag must be recommended. Give a summary of the movies and why the human should watch them. \n", + " Put the email between tags.\n", + "\n", + " \n", + " {result}\n", + " \n", + "\n", + " Assistant:\n", + " \"\"\"\n", + "\n", + "RANDOM_PROMPT_2 = PromptTemplate(\n", + " input_variables=[\"result\"], template=RANDOM_PROMPT_QUERY_2\n", + ")\n", + "personalize_chain_instance = AmazonPersonalizeChain.from_llm(\n", + " llm=bedrock_llm, client=client, return_direct=True\n", + ")\n", + "random_chain_instance = LLMChain(llm=bedrock_llm, prompt=RANDOM_PROMPT_2)\n", + "overall_chain = SequentialChain(\n", + " chains=[personalize_chain_instance, random_chain_instance],\n", + " input_variables=[\"user_id\"],\n", + " verbose=True,\n", + ")\n", + "overall_chain.run({\"user_id\": \"1\", \"item_id\": \"234\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "### 2.5 [Use-case-5] Invoke Amazon Personalize and retrieve metadata " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "recommender_arn = \"\"\n", + "metadata_column_names = [\n", + " \"\",\n", + " \"\",\n", + "]\n", + "metadataMap = {\"ITEMS\": metadata_column_names}\n", + "\n", + "client = AmazonPersonalize(\n", + " credentials_profile_name=\"default\",\n", + " region_name=\"us-west-2\",\n", + " recommender_arn=recommender_arn,\n", + ")\n", + "client.get_recommendations(user_id=\"1\", metadataColumns=metadataMap)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "### 2.6 [Use-Case 6] Invoke Personalize Chain with returned metadata for summarizing results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "bedrock_llm = Bedrock(model_id=\"anthropic.claude-v2\", region_name=\"us-west-2\")\n", + "\n", + "# Create personalize chain\n", + "# Use return_direct=True if you do not want summary\n", + "chain = AmazonPersonalizeChain.from_llm(\n", + " llm=bedrock_llm, client=client, return_direct=False\n", + ")\n", + "response = chain({\"user_id\": \"1\", \"metadata_columns\": metadataMap})\n", + "print(response)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + }, + "vscode": { + "interpreter": { + "hash": "15e58ce194949b77a891bd4339ce3d86a9bd138e905926019517993f97db9e6c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/api_reference/conf.py b/docs/api_reference/conf.py index e993048fc57f4..36f34a44598dd 100644 --- a/docs/api_reference/conf.py +++ b/docs/api_reference/conf.py @@ -114,8 +114,8 @@ def setup(app): autodoc_member_order = "groupwise" autoclass_content = "both" autodoc_typehints_format = "short" +autodoc_typehints = "both" -# autodoc_typehints = "description" # Add any paths that contain templates here, relative to this directory. templates_path = ["templates"] diff --git a/docs/api_reference/themes/scikit-learn-modern/search.html b/docs/api_reference/themes/scikit-learn-modern/search.html index a1ededafb5240..2c9f40f15a6cc 100644 --- a/docs/api_reference/themes/scikit-learn-modern/search.html +++ b/docs/api_reference/themes/scikit-learn-modern/search.html @@ -5,7 +5,7 @@ - +