diff --git a/templates/pii-protected-chatbot/LICENSE b/templates/pii-protected-chatbot/LICENSE new file mode 100644 index 000000000..426b65090 --- /dev/null +++ b/templates/pii-protected-chatbot/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 LangChain, Inc. + +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. diff --git a/templates/pii-protected-chatbot/README.md b/templates/pii-protected-chatbot/README.md new file mode 100644 index 000000000..95916c574 --- /dev/null +++ b/templates/pii-protected-chatbot/README.md @@ -0,0 +1 @@ +# pii-protected-chatbot diff --git a/templates/pii-protected-chatbot/pii_protected_chatbot/__init__.py b/templates/pii-protected-chatbot/pii_protected_chatbot/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/templates/pii-protected-chatbot/pii_protected_chatbot/chain.py b/templates/pii-protected-chatbot/pii_protected_chatbot/chain.py new file mode 100644 index 000000000..d7d502ae8 --- /dev/null +++ b/templates/pii-protected-chatbot/pii_protected_chatbot/chain.py @@ -0,0 +1,85 @@ +from typing import List, Tuple + +from langchain.chat_models import ChatOpenAI +from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain.pydantic_v1 import BaseModel +from langchain.schema.messages import AIMessage, HumanMessage +from langchain.schema.output_parser import StrOutputParser +from langchain.schema.runnable 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) diff --git a/templates/pii-protected-chatbot/pyproject.toml b/templates/pii-protected-chatbot/pyproject.toml new file mode 100644 index 000000000..01065eb5d --- /dev/null +++ b/templates/pii-protected-chatbot/pyproject.toml @@ -0,0 +1,24 @@ +[tool.poetry] +name = "pii_protected_chatbot" +version = "0.0.1" +description = "" +authors = [] +readme = "README.md" + +[tool.poetry.dependencies] +python = ">=3.8.1,<4.0" +langchain = ">=0.0.313, <0.1" +openai = "^0.28.1" + +[tool.poetry.group.dev.dependencies] +langchain-cli = ">=0.0.4" +fastapi = "^0.104.0" +sse-starlette = "^1.6.5" + +[tool.langserve] +export_module = "pii_protected_chatbot.chain" +export_attr = "chain" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/templates/pii-protected-chatbot/tests/__init__.py b/templates/pii-protected-chatbot/tests/__init__.py new file mode 100644 index 000000000..e69de29bb