-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate Slack App with Pinecone #12
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
3bb8d74
Add pinecone vector database
20001LastOrder b604bb6
Merge main
20001LastOrder 187a274
Merge pull request #1 from 20001LastOrder/slack-app
20001LastOrder 3fe13c1
Respond to a thread and use the thread as chat history
20001LastOrder 0adca8a
Merge branch 'main' of https://github.com/20001LastOrder/practical-llms
20001LastOrder 6d3f92e
script for loading record to pinecone
ChenKua f3f2762
add citation for readthedoc
YujingYang666777 861ff29
Merged branch 'main' of https://github.com/20001LastOrder/practical-llms
YujingYang666777 0403255
Integrate local databases
20001LastOrder e8643ec
update readme
20001LastOrder 4ab30a6
Merge main of the main repo
20001LastOrder a019565
Merge branch 'main' into main
20001LastOrder File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
__pycache__ | ||
**/.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,4 +21,4 @@ COPY . . | |
EXPOSE 80 | ||
|
||
# Run the Flask app | ||
CMD ["python", "app.py"] | ||
CMD ["python", "bolt_app.py"] | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
############################################## | ||
# Implementation of the slack app using Bolt | ||
# Importing necessary modules | ||
############################################## | ||
|
||
import os | ||
from dotenv import load_dotenv | ||
load_dotenv() | ||
from langchain.chat_models import ChatOpenAI | ||
from langchain import LLMChain | ||
from langchain.chains.question_answering import load_qa_chain | ||
from langchain.embeddings.openai import OpenAIEmbeddings | ||
from langchain.text_splitter import CharacterTextSplitter | ||
from langchain.vectorstores import FAISS | ||
from langchain.llms import OpenAI | ||
from os import environ | ||
from vectorstores import ConversationStore | ||
from prompt import SlackBotPrompt | ||
from slack_bolt import App | ||
|
||
|
||
|
||
# This `app` represents your existing Flask app | ||
app = App( | ||
token=os.environ.get("SLACK_OAUTH_TOKEN"), | ||
signing_secret=os.environ.get("SLACK_SIGNING_SECRET"), | ||
) | ||
|
||
|
||
##################################################################################################### | ||
# Setting up environment variables and Slack configuration: | ||
# The code retrieves various environment variables using os.environ.get() method. | ||
# Environment variables include Slack signing secret, OAuth token, verification token, and OpenAI key. | ||
##################################################################################################### | ||
|
||
SLACK_SIGNING_SECRET = environ.get("SLACK_SIGNING_SECRET") | ||
SLACK_OAUTH_TOKEN = environ.get("SLACK_OAUTH_TOKEN") | ||
VERIFICATION_TOKEN = environ.get("VERIFICATION_TOKEN") | ||
OPENAI_KEY=environ.get("OPENAI_KEY") | ||
|
||
|
||
|
||
########################################################################### | ||
# Instantiating Slack client and Flask app: | ||
########################################################################### | ||
|
||
#instantiating slack client | ||
os.environ['OPENAI_API_KEY'] = OPENAI_KEY | ||
|
||
@app.command("/hello-socket-mode") | ||
def hello_command(ack, body): | ||
user_id = body["user_id"] | ||
ack(f"Hi, <@{user_id}>!") | ||
|
||
bot = app.client.auth_test() | ||
print(bot) | ||
|
||
@app.event("app_mention") | ||
def event_test(client, say, event): | ||
question = event['text'] | ||
|
||
thread_ts = event.get("thread_ts", None) or event["ts"] | ||
replies = client.conversations_replies(channel=event['channel'], ts=thread_ts) | ||
previous_messages = replies['messages'][:-1] | ||
|
||
results = get_response(question, previous_messages) | ||
|
||
say(results, thread_ts=thread_ts) | ||
|
||
@app.event("app_home_opened") | ||
def update_home_tab(client, event, logger): | ||
try: | ||
# views.publish is the method that your app uses to push a view to the Home tab | ||
client.views_publish( | ||
# the user that opened your app's app home | ||
user_id=event["user"], | ||
# the view object that appears in the app home | ||
view={ | ||
"type": "home", | ||
"callback_id": "home_view", | ||
|
||
# body of the view | ||
"blocks": [ | ||
{ | ||
"type": "section", | ||
"text": { | ||
"type": "mrkdwn", | ||
"text": "*Welcome to your _App's Home_* :tada:" | ||
} | ||
}, | ||
{ | ||
"type": "divider" | ||
}, | ||
{ | ||
"type": "section", | ||
"text": { | ||
"type": "mrkdwn", | ||
"text": "This button won't do much for now but you can set up a listener for it using the `actions()` method and passing its unique `action_id`. See an example in the `examples` folder within your Bolt app." | ||
} | ||
}, | ||
{ | ||
"type": "actions", | ||
"elements": [ | ||
{ | ||
"type": "button", | ||
"text": { | ||
"type": "plain_text", | ||
"text": "Click me!" | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
) | ||
|
||
except Exception as e: | ||
logger.error(f"Error publishing home tab: {e}") | ||
|
||
def get_response(question, previous_messages): | ||
llm = ChatOpenAI( | ||
openai_api_key=OPENAI_KEY, request_timeout=120 | ||
) | ||
|
||
prompt = SlackBotPrompt( | ||
ai_name='Sherpa', | ||
ai_id=bot['user_id'], | ||
token_counter=llm.get_num_tokens, | ||
input_variables=['query', 'messages', 'retriever'] | ||
) | ||
|
||
retriever = ConversationStore.get_vector_retrieval( | ||
'ReadTheDocs', OPENAI_KEY, index_name=os.getenv("PINECONE_INDEX") | ||
) | ||
|
||
chain = LLMChain(llm=llm, prompt=prompt) | ||
|
||
return chain.run( | ||
query=question, | ||
messages=previous_messages, | ||
retriever=retriever, | ||
) | ||
|
||
# Start the server on port 3000 | ||
if __name__ == "__main__": | ||
# documents = getDocuments('files') | ||
# vectorstore = getVectoreStore(documents) | ||
# qa = createLangchainQA(vectorstore) | ||
|
||
# chain = createIndex("files") | ||
print('Running the app') | ||
app.start() | ||
# SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
from pydantic import BaseModel | ||
from langchain.prompts.chat import BaseChatPromptTemplate | ||
from typing import Callable, Any, List | ||
from langchain.schema import ( | ||
BaseMessage, | ||
HumanMessage, | ||
SystemMessage, | ||
AIMessage | ||
) | ||
import time | ||
from langchain.vectorstores.base import VectorStoreRetriever | ||
|
||
|
||
|
||
class SlackBotPrompt(BaseChatPromptTemplate, BaseModel): | ||
ai_name: str | ||
ai_id: str | ||
token_counter: Callable[[str], int] | ||
send_token_limit: int = 4196 | ||
|
||
def construct_base_prompt(self): | ||
full_prompt = ( | ||
f"You are a friendly assistent bot called {self.ai_name}\n\n" | ||
) | ||
|
||
return full_prompt | ||
|
||
def format_messages(self, **kwargs: Any) -> List[BaseMessage]: | ||
base_prompt = SystemMessage( | ||
content=self.construct_base_prompt() | ||
) | ||
time_prompt = SystemMessage( | ||
content=f"The current time and date is {time.strftime('%c')}" | ||
) | ||
used_tokens = self.token_counter(base_prompt.content) + self.token_counter( | ||
time_prompt.content | ||
) | ||
|
||
query = kwargs["query"] | ||
retriever: VectorStoreRetriever = kwargs["retriever"] | ||
previous_messages = self.process_chat_history(kwargs["messages"]) | ||
|
||
# retrieve relevant documents for the query | ||
relevant_docs = retriever.get_relevant_documents(query) | ||
relevant_memory = ["Document: " + d.page_content + "\nLink" + d.metadata["source"] + "\n" for d in relevant_docs] | ||
|
||
# remove documents from memory until the token limit is reached | ||
relevant_memory_tokens = sum( | ||
[self.token_counter(doc) for doc in relevant_memory] | ||
) | ||
while used_tokens + relevant_memory_tokens > 2500: | ||
relevant_memory = relevant_memory[:-1] | ||
relevant_memory_tokens = sum( | ||
[self.token_counter(doc) for doc in relevant_memory] | ||
) | ||
|
||
content_format = ( | ||
f"Here are some documents that may be relevant to the topic:" | ||
f"\n{relevant_memory}\n\n" | ||
) | ||
|
||
input_message = ( | ||
f"Use the above information to respond to the user's message:\n{query}\n\n" | ||
f"create inline citation by adding the source link of the reference document at the of the sentence." | ||
f"Only use the link given in the reference document. DO NOT create link by yourself." | ||
) | ||
|
||
# print(content_format) | ||
|
||
memory_message = SystemMessage(content=content_format) | ||
used_tokens += self.token_counter(memory_message.content) | ||
historical_messages: List[BaseMessage] = [] | ||
print(previous_messages) | ||
for message in previous_messages[-10:][::-1]: | ||
message_tokens = self.token_counter(message.content) | ||
if used_tokens + message_tokens > self.send_token_limit - 1000: | ||
break | ||
historical_messages = [message] + historical_messages | ||
used_tokens += message_tokens | ||
print(historical_messages) | ||
|
||
input_message = HumanMessage(content=input_message) | ||
|
||
messages: List[BaseMessage] = [base_prompt, time_prompt, memory_message] | ||
messages += historical_messages | ||
messages.append(input_message) | ||
|
||
return messages | ||
|
||
def process_chat_history(self, messages: List[dict]) -> List[BaseMessage]: | ||
results = [] | ||
|
||
for message in messages: | ||
print(message) | ||
if message['type'] != 'message' and message['type'] != 'text': | ||
continue | ||
|
||
message_cls = AIMessage if message['user'] == self.ai_id else HumanMessage | ||
# replace the at in the message with the name of the bot | ||
text = message['text'].replace(f'@{self.ai_id}', f'@{self.ai_name}') | ||
results.append(message_cls(content=text)) | ||
|
||
return results | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,6 @@ unstructured | |
openai | ||
chromadb | ||
tiktoken | ||
Flask-Cors==3.0.10 | ||
slack_bolt | ||
pinecone-client | ||
Flask-Cors==3.0.10 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the new app that utilize pine cone. I didn’t change the other app.py file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you resolve thw conflict then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done