seansullivan/Langchain-Docs-June-26-2024 huggingface dataset:
{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "681a5d1e",
   "metadata": {},
   "source": [
    "## Run Template\n",
    "\n",
    "In `server.py`, set -\n",
    "```\n",
    "from fastapi import FastAPI\n",
    "from langserve import add_routes\n",
    "from propositional_retrieval import chain\n",
    "\n",
    "app = FastAPI(\n",
    "    title=\"LangChain Server\",\n",
    "    version=\"1.0\",\n",
    "    description=\"Retriever and Generator for RAG Chroma Dense Retrieval\",\n",
    ")\n",
    "\n",
    "add_routes(app, chain, path=\"/propositional-retrieval\")\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    import uvicorn\n",
    "\n",
    "    uvicorn.run(app, host=\"localhost\", port=8000)\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d774be2a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langserve.client import RemoteRunnable\n",
    "\n",
    "rag_app = RemoteRunnable(\"http://localhost:8001/propositional-retrieval\")\n",
    "rag_app.invoke(\"How are transformers related to convolutional neural networks?\")"
   ]
  }
 ],
 "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.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
from langchain_community.chat_models import ChatOpenAI
from langchain_core.load import load
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel
from langchain_core.runnables import RunnablePassthrough

from propositional_retrieval.constants import DOCSTORE_ID_KEY
from propositional_retrieval.storage import get_multi_vector_retriever


def format_docs(docs: list) -> str:
    loaded_docs = [load(doc) for doc in docs]
    return "\n".join(
        [
            f"<Document id={i}>\n{doc.page_content}\n</Document>"
            for i, doc in enumerate(loaded_docs)
        ]
    )


def rag_chain(retriever):
    """
    The RAG chain

    :param retriever: A function that retrieves the necessary context for the model.
    :return: A chain of functions representing the multi-modal RAG process.
    """
    model = ChatOpenAI(temperature=0, model="gpt-4-1106-preview", max_tokens=1024)
    prompt = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                "You are an AI assistant. Answer based on the retrieved documents:"
                "\n<Documents>\n{context}\n</Documents>",
            ),
            ("user", "{question}?"),
        ]
    )

    # Define the RAG pipeline
    chain = (
        {
            "context": retriever | format_docs,
            "question": RunnablePassthrough(),
        }
        | prompt
        | model
        | StrOutputParser()
    )

    return chain


# Create the multi-vector retriever
retriever = get_multi_vector_retriever(DOCSTORE_ID_KEY)

# Create RAG chain
chain = rag_chain(retriever)


# Add typing for input
class Question(BaseModel):
    __root__: str


chain = chain.with_types(input_type=Question)
import logging
import uuid
from typing import Sequence

from bs4 import BeautifulSoup as Soup
from langchain_core.documents import Document
from langchain_core.runnables import Runnable

from propositional_retrieval.constants import DOCSTORE_ID_KEY
from propositional_retrieval.proposal_chain import proposition_chain
from propositional_retrieval.storage import get_multi_vector_retriever

logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(__name__)


def add_documents(
    retriever,
    propositions: Sequence[Sequence[str]],
    docs: Sequence[Document],
    id_key: str = DOCSTORE_ID_KEY,
):
    doc_ids = [
        str(uuid.uuid5(uuid.NAMESPACE_DNS, doc.metadata["source"])) for doc in docs
    ]
    prop_docs = [
        Document(page_content=prop, metadata={id_key: doc_ids[i]})
        for i, props in enumerate(propositions)
        for prop in props
        if prop
    ]
    retriever.vectorstore.add_documents(prop_docs)
    retriever.docstore.mset(list(zip(doc_ids, docs)))


def create_index(
    docs: Sequence[Document],
    indexer: Runnable,
    docstore_id_key: str = DOCSTORE_ID_KEY,
):
    """
    Create retriever that indexes docs and their propositions

    :param docs: Documents to index
    :param indexer: Runnable creates additional propositions per doc
    :param docstore_id_key: Key to use to store the docstore id
    :return: Retriever
    """
    logger.info("Creating multi-vector retriever")
    retriever = get_multi_vector_retriever(docstore_id_key)
    propositions = indexer.batch(
        [{"input": doc.page_content} for doc in docs], {"max_concurrency": 10}
    )

    add_documents(
        retriever,
        propositions,
        docs,
        id_key=docstore_id_key,
    )

    return retriever


if __name__ == "__main__":
    # For our example, we'll load docs from the web
    from langchain_text_splitters import RecursiveCharacterTextSplitter  # noqa
    from langchain_community.document_loaders.recursive_url_loader import (
        RecursiveUrlLoader,
    )

    # The attention is all you need paper
    # Could add more parsing here, as it's very raw.
    loader = RecursiveUrlLoader(
        "https://ar5iv.labs.arxiv.org/html/1706.03762",
        max_depth=2,
        extractor=lambda x: Soup(x, "html.parser").text,
    )
    data = loader.load()
    logger.info(f"Loaded {len(data)} documents")

    # Split
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=8000, chunk_overlap=0)
    all_splits = text_splitter.split_documents(data)
    logger.info(f"Split into {len(all_splits)} documents")

    # Create retriever
    retriever_multi_vector_img = create_index(
        all_splits,
        proposition_chain,
        DOCSTORE_ID_KEY,
    )
import logging
from pathlib import Path

from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.storage import LocalFileStore
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(__name__)


def get_multi_vector_retriever(docstore_id_key: str):
    """Create the composed retriever object."""
    vectorstore = get_vectorstore()
    store = get_docstore()
    return MultiVectorRetriever(
        vectorstore=vectorstore,
        byte_store=store,
        id_key=docstore_id_key,
    )


def get_vectorstore(collection_name: str = "proposals"):
    """Get the vectorstore used for this example."""
    return Chroma(
        collection_name=collection_name,
        persist_directory=str(Path(__file__).parent.parent / "chroma_db_proposals"),
        embedding_function=OpenAIEmbeddings(),
    )


def get_docstore():
    """Get the metadata store used for this example."""
    return LocalFileStore(
        str(Path(__file__).parent.parent / "multi_vector_retriever_metadata")
    )
# plate-chain

This template enables parsing of data from laboratory plates. 

In the context of biochemistry or molecular biology, laboratory plates are commonly used tools to hold samples in a grid-like format. 

This can parse the resulting data into standardized (e.g., JSON) format for further processing.

## Environment Setup

Set the `OPENAI_API_KEY` environment variable to access the OpenAI models.

## Usage

To utilize plate-chain, you must have the LangChain CLI installed:

```shell
pip install -U langchain-cli
```

Creating a new LangChain project and installing plate-chain as the only package can be done with:

```shell
langchain app new my-app --package plate-chain
```

If you wish to add this to an existing project, simply run:

```shell
langchain app add plate-chain
```

Then add the following code to your `server.py` file:

```python
from plate_chain import chain as plate_chain

add_routes(app, plate_chain, path="/plate-chain")
```

(Optional) For configuring LangSmith, which helps trace, monitor and debug LangChain applications, use the following code:

```shell
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=<your-api-key>
export LANGCHAIN_PROJECT=<your-project>  # if not specified, defaults to "default"
```

If you're in this directory, you can start a LangServe instance directly by:

```shell
langchain serve
```

This starts the FastAPI app with a server running locally at 
[http://localhost:8000](http://localhost:8000)

All templates can be viewed at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
Access the playground at [http://127.0.0.1:8000/plate-chain/playground](http://127.0.0.1:8000/plate-chain/playground)  

You can access the template from code with:

```python
from langserve.client import RemoteRunnable

runnable = RemoteRunnable("http://localhost:8000/plate-chain")
```
import base64
import json

from langchain_community.chat_models import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate
from langchain_core.pydantic_v1 import Field
from langserve import CustomUserType

from .prompts import (
    AI_REPONSE_DICT,
    FULL_PROMPT,
    USER_EXAMPLE_DICT,
    create_prompt,
)
from .utils import parse_llm_output

llm = ChatOpenAI(temperature=0, model="gpt-4")

prompt = ChatPromptTemplate.from_messages(
    [
        SystemMessagePromptTemplate.from_template(FULL_PROMPT),
        ("human", "{user_example}"),
        ("ai", "{ai_response}"),
        ("human", "{input}"),
    ],
)


# ATTENTION: Inherit from CustomUserType instead of BaseModel otherwise
# the server will decode it into a dict instead of a pydantic model.
class FileProcessingRequest(CustomUserType):
    """Request including a base64 encoded file."""

    # The extra field is used to specify a widget for the playground UI.
    file: str = Field(..., extra={"widget": {"type": "base64file"}})
    num_plates: int = None
    num_rows: int = 8
    num_cols: int = 12


def _load_file(request: FileProcessingRequest):
    return base64.b64decode(request.file.encode("utf-8")).decode("utf-8")


def _load_prompt(request: FileProcessingRequest):
    return create_prompt(
        num_plates=request.num_plates,
        num_rows=request.num_rows,
        num_cols=request.num_cols,
    )


def _get_col_range_str(request: FileProcessingRequest):
    if request.num_cols:
        return f"from 1 to {request.num_cols}"
    else:
        return ""


def _get_json_format(request: FileProcessingRequest):
    return json.dumps(
        [
            {
                "row_start": 12,
                "row_end": 12 + request.num_rows - 1,
                "col_start": 1,
                "col_end": 1 + request.num_cols - 1,
                "contents": "Entity ID",
            }
        ]
    )


chain = (
    {
        # Should add validation to ensure numeric indices
        "input": _load_file,
        "hint": _load_prompt,
        "col_range_str": _get_col_range_str,
        "json_format": _get_json_format,
        "user_example": lambda x: USER_EXAMPLE_DICT[x.num_rows * x.num_cols],
        "ai_response": lambda x: AI_REPONSE_DICT[x.num_rows * x.num_cols],
    }
    | prompt
    | llm
    | StrOutputParser()
    | parse_llm_output
).with_types(input_type=FileProcessingRequest)
import json

from langchain_core.pydantic_v1 import BaseModel, Field, conint


class LLMPlateResponse(BaseModel):
    row_start: conint(ge=0) = Field(
        ..., description="The starting row of the plate (0-indexed)"
    )
    row_end: conint(ge=0) = Field(
        ..., description="The ending row of the plate (0-indexed)"
    )
    col_start: conint(ge=0) = Field(
        ..., description="The starting column of the plate (0-indexed)"
    )
    col_end: conint(ge=0) = Field(
        ..., description="The ending column of the plate (0-indexed)"
    )
    contents: str


def parse_llm_output(result: str):
    """
    Based on the prompt we expect the result to be a string that looks like:

    '[{"row_start": 12, "row_end": 19, "col_start": 1, \
    "col_end": 12, "contents": "Entity ID"}]'

    We'll load that JSON and turn it into a Pydantic model
    """
    return [LLMPlateResponse(**plate_r) for plate_r in json.loads(result)]
# pirate-speak

This template converts user input into pirate speak.

## Environment Setup

Set the `OPENAI_API_KEY` environment variable to access the OpenAI models.

## Usage

To use this package, you should first have the LangChain CLI installed:

```shell
pip install -U langchain-cli
```

To create a new LangChain project and install this as the only package, you can do:

```shell
langchain app new my-app --package pirate-speak
```

If you want to add this to an existing project, you can just run:

```shell
langchain app add pirate-speak
```

And add the following code to your `server.py` file:
```python
from pirate_speak.chain import chain as pirate_speak_chain

add_routes(app, pirate_speak_chain, path="/pirate-speak")
```

(Optional) Let's now configure LangSmith. 
LangSmith will help us trace, monitor and debug LangChain applications. 
You can sign up for LangSmith [here](https://smith.langchain.com/). 
If you don't have access, you can skip this section


```shell
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=<your-api-key>
export LANGCHAIN_PROJECT=<your-project>  # if not specified, defaults to "default"
```

If you are inside this directory, then you can spin up a LangServe instance directly by:

```shell
langchain serve
```

This will start the FastAPI app with a server is running locally at 
[http://localhost:8000](http://localhost:8000)

We can see all templates at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
We can access the playground at [http://127.0.0.1:8000/pirate-speak/playground](http://127.0.0.1:8000/pirate-speak/playground)  

We can access the template from code with:

```python
from langserve.client import RemoteRunnable

runnable = RemoteRunnable("http://localhost:8000/pirate-speak")
```
from langchain_community.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

_prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Translate user input into pirate speak",
        ),
        MessagesPlaceholder("chat_history"),
        ("human", "{text}"),
    ]
)
_model = ChatOpenAI()

# if you update this, you MUST also update ../pyproject.toml
# with the new `tool.langserve.export_attr`
chain = _prompt | _model
# pirate-speak-configurable

This template converts user input into pirate speak. It shows how you can allow
`configurable_alternatives` in the Runnable, allowing you to select from 
OpenAI, Anthropic, or Cohere as your LLM Provider in the playground (or via API).

## Environment Setup

Set the following environment variables to access all 3 configurable alternative
model providers:

- `OPENAI_API_KEY`
- `ANTHROPIC_API_KEY`
- `COHERE_API_KEY`

## Usage

To use this package, you should first have the LangChain CLI installed:

```shell
pip install -U langchain-cli
```

To create a new LangChain project and install this as the only package, you can do:

```shell
langchain app new my-app --package pirate-speak-configurable
```

If you want to add this to an existing project, you can just run:

```shell
langchain app add pirate-speak-configurable
```

And add the following code to your `server.py` file:
```python
from pirate_speak_configurable import chain as pirate_speak_configurable_chain

add_routes(app, pirate_speak_configurable_chain, path="/pirate-speak-configurable")
```

(Optional) Let's now configure LangSmith. 
LangSmith will help us trace, monitor and debug LangChain applications. 
You can sign up for LangSmith [here](https://smith.langchain.com/). 
If you don't have access, you can skip this section


```shell
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=<your-api-key>
export LANGCHAIN_PROJECT=<your-project>  # if not specified, defaults to "default"
```

If you are inside this directory, then you can spin up a LangServe instance directly by:

```shell
langchain serve
```

This will start the FastAPI app with a server is running locally at 
[http://localhost:8000](http://localhost:8000)

We can see all templates at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
We can access the playground at [http://127.0.0.1:8000/pirate-speak-configurable/playground](http://127.0.0.1:8000/pirate-speak-configurable/playground)  

We can access the template from code with:

```python
from langserve.client import RemoteRunnable

runnable = RemoteRunnable("http://localhost:8000/pirate-speak-configurable")
```
from langchain_community.chat_models import ChatAnthropic, ChatCohere, ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import ConfigurableField

_prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Translate user input into pirate speak",
        ),
        ("human", "{text}"),
    ]
)
_model = ChatOpenAI().configurable_alternatives(
    ConfigurableField(id="llm_provider"),
    default_key="openai",
    anthropic=ChatAnthropic,
    cohere=ChatCohere,
)

# if you update this, you MUST also update ../pyproject.toml
# with the new `tool.langserve.export_attr`
chain = _prompt | _model
# pii-protected-chatbot

This template creates a chatbot that flags any incoming PII and doesn't pass it to the LLM.

## Environment Setup

The following environment variables need to be set:

Set the `OPENAI_API_KEY` environment variable to access the OpenAI models.

## Usage

To use this package, you should first have the LangChain CLI installed:

```shell
pip install -U "langchain-cli[serve]"
```

To create a new LangChain project and install this as the only package, you can do:

```shell
langchain app new my-app --package pii-protected-chatbot
```

If you want to add this to an existing project, you can just run:

```shell
langchain app add pii-protected-chatbot
```

And add the following code to your `server.py` file:
```python
from pii_protected_chatbot.chain import chain as pii_protected_chatbot

add_routes(app, pii_protected_chatbot, path="/openai-functions-agent")
```

(Optional) Let's now configure LangSmith. 
LangSmith will help us trace, monitor and debug LangChain applications. 
You can sign up for LangSmith [here](https://smith.langchain.com/). 
If you don't have access, you can skip this section

```shell
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=<your-api-key>
export LANGCHAIN_PROJECT=<your-project>  # if not specified, defaults to "default"
```

If you are inside this directory, then you can spin up a LangServe instance directly by:

```shell
langchain serve
```

This will start the FastAPI app with a server is running locally at 
[http://localhost:8000](http://localhost:8000)

We can see all templates at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
We can access the playground at [http://127.0.0.1:8000/pii_protected_chatbot/playground](http://127.0.0.1:8000/pii_protected_chatbot/playground)  

We can access the template from code with:

```python
from langserve.client import RemoteRunnable

runnable = RemoteRunnable("http://localhost:8000/pii_protected_chatbot")
```
from typing import List, Tuple

from langchain_community.chat_models import ChatOpenAI
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.pydantic_v1 import BaseModel
from langchain_core.runnables import RunnablePassthrough
from presidio_analyzer import AnalyzerEngine


# Formatting for chat history
def _format_chat_history(chat_history: List[Tuple[str, str]]):
    buffer = []
    for human, ai in chat_history:
        buffer.append(HumanMessage(content=human))
        buffer.append(AIMessage(content=ai))
    return buffer


# Prompt we will use
_prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful assistant who speaks like a pirate",
        ),
        MessagesPlaceholder(variable_name="chat_history"),
        ("human", "{text}"),
    ]
)

# Model we will use
_model = ChatOpenAI()

# Standard conversation chain.
chat_chain = (
    {
        "chat_history": lambda x: _format_chat_history(x["chat_history"]),
        "text": lambda x: x["text"],
    }
    | _prompt
    | _model
    | StrOutputParser()
)

# PII Detection logic
analyzer = AnalyzerEngine()


# You can customize this to detect any PII
def _detect_pii(inputs: dict) -> bool:
    analyzer_results = analyzer.analyze(text=inputs["text"], language="en")
    return bool(analyzer_results)


# Add logic to route on whether PII has been detected
def _route_on_pii(inputs: dict):
    if inputs["pii_detected"]:
        # Response if PII is detected
        return "Sorry, I can't answer questions that involve PII"
    else:
        return chat_chain


# Final chain
chain = RunnablePassthrough.assign(
    # First detect PII
    pii_detected=_detect_pii
) | {
    # Then use this information to generate the response
    "response": _route_on_pii,
    # Return boolean of whether PII is detected so client can decided
    # whether or not to include in chat history
    "pii_detected": lambda x: x["pii_detected"],
}


# Add typing for playground
class ChainInput(BaseModel):
    text: str
    chat_history: List[Tuple[str, str]]


chain = chain.with_types(input_type=ChainInput)