Skip to content
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

Dev #9

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Changes from 2 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b48bac5
Project Outline Update
Sep 30, 2024
1c0357e
Project Reserach Updates
Oct 7, 2024
1835f3a
EDA updates
Oct 21, 2024
3dc3ba7
POC commit.
Nov 4, 2024
cb24c02
extract text from pdf
Nov 6, 2024
a25dfc9
Merge pull request #1 from BU-Spark/dev_akshat
akshatgurbuxani Nov 7, 2024
2d5430a
Merge pull request #3 from BU-Spark/dev_akshat_eda
akshatgurbuxani Nov 7, 2024
eb80ec6
Merge pull request #4 from BU-Spark/dev_abhaya_poc
akshatgurbuxani Nov 12, 2024
49006b8
Add files via upload
xud0218 Nov 22, 2024
4474120
Delete project-poc/BPS_chatbot.ipynb
xud0218 Nov 22, 2024
02c0d9c
implemented new features
xud0218 Nov 25, 2024
b69b79a
developed ui part
xud0218 Nov 27, 2024
a5e1464
Delete BPS_beta_screenshot.png
xud0218 Nov 27, 2024
c39ad90
Add files via upload
xud0218 Nov 27, 2024
2f136d9
Changes to fetch links
Dec 3, 2024
7571c7b
UI commit.
mcakuraju5 Dec 5, 2024
246ec7b
Add files via upload
xud0218 Dec 6, 2024
a15197e
Merge pull request #7 from BU-Spark/dev_mounika
akshatgurbuxani Dec 8, 2024
0506cf1
Merge pull request #6 from BU-Spark/dev_akshat
akshatgurbuxani Dec 8, 2024
94b99ca
Chatbot commit
Dec 9, 2024
ea0f690
Merge pull request #8 from BU-Spark/akshat_final
akshatgurbuxani Dec 10, 2024
7ab9bce
Delete project-UI directory
xud0218 Dec 10, 2024
10b6659
Fixed file paths. Add data folder. Updated README.md and DATASETDOC-f…
Dec 11, 2024
5a4c4c7
Provided links to main branch
Dec 11, 2024
f172d9c
Delete BPS_chatbot_with_ui directory
xud0218 Dec 11, 2024
c1ed5dd
Add files via upload
xud0218 Dec 11, 2024
ae143e2
Delete BPS_chatbot_with_ui directory
xud0218 Dec 11, 2024
546f7d9
Add files via upload
xud0218 Dec 11, 2024
83819ae
Update README.md
xud0218 Dec 11, 2024
d343cbf
Update README.md
xud0218 Dec 11, 2024
99c4483
Update app.py
xud0218 Dec 11, 2024
a3effa1
Merge pull request #10 from BU-Spark/akshat_final
akshatgurbuxani Dec 12, 2024
5797c5d
Merge pull request #11 from BU-Spark/xud
trgardos Dec 16, 2024
14027c0
Update README.md
trgardos Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions project-UI/chainlitmain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import chainlit as cl
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
import os
import json

os.environ["OPENAI_API_KEY"] = "OPENAI_API_KEY"

# Initialize Embeddings and FAISS
modelPath = "sentence-transformers/all-MiniLM-l6-v2"

embeddings = HuggingFaceEmbeddings(
model_name=modelPath,
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': False}
)

# Load FAISS Index
loaded_db = FAISS.load_local("code/faiss_index", embeddings, allow_dangerous_deserialization=True)
retriever = loaded_db.as_retriever(search_type="similarity", search_kwargs={"k": 4})

# LLM Configuration
llm = ChatOpenAI(model="gpt-4o-mini")

# Prompt Template
template = """
You are a highly knowledgeable and professional policy advisor for Boston Public Schools. Your role is to provide precise, context-specific answers to questions based solely on the information provided in the context.

### Guidelines:
1. **Scope Limitation**: Only use the information provided in the "Context" to answer the question. Do not infer, assume, or incorporate external information.
2. **Out-of-Scope Questions**: If a question is unrelated to any policy, politely respond that it is beyond the scope of your knowledge as a policy advisor and feel free to continue the answer based on the "question". Finally, append "[0]__[0]" at the end of the answer for the developer to use, only if the "question" is unrelated to the task.
3. **Citing Policy**: Always conclude your response by explicitly citing the policy name(s) used to formulate your answer. If no policy is applicable, don't mention anything.

### Additional Considerations:
- **Ambiguities**: If the context lacks sufficient information to answer the question definitively, mention this and provide a response based on the provided context.
- **Clarity and Professionalism**: Ensure all responses are concise but comprehensive, clear, and professional.

### Input Structure:
Context: {context}
Question: {question}
"""

custom_rag_prompt = PromptTemplate.from_template(template)

def format_docs(docs):
return "\n\n".join(
f"{doc.page_content}\n\nSource: {doc.metadata.get('file_name', 'Unknown File')}, Folder: {doc.metadata.get('folder_name', 'Unknown Folder')}"
for doc in docs
)

rag_chain = (
{
"context": retriever | format_docs,
"question": RunnablePassthrough()
}
| custom_rag_prompt
| llm
| StrOutputParser()
)

@cl.on_chat_start
async def on_chat_start():
"""
Initializes the chatbot session.
"""
await cl.Message(
content="Hi! I am the policy advisor for Boston Public School. How can I assist you today?"
).send()

@cl.on_message
async def on_message(message: cl.Message):
"""
Handles user queries and returns answers based on retrieved documents.
"""
try:
# Invoke the RAG chain to get the main response
response = rag_chain.invoke(message.content)

marker = "[0]__[0]"
# Check if the response contains the marker
if marker in response:
# Remove the marker from the response
full_response = response.replace(marker, "").strip()
else:
# Retrieve relevant documents
retrieved_documents = retriever.invoke(message.content)

# Initialize a list to collect formatted links
links = []
for i, item in enumerate(retrieved_documents, 1): # Iterate through the list of Document objects
link = item.metadata.get('link') # Access the 'link' key within the 'metadata' attribute
file_name = item.metadata.get('file_name') # Access the 'file_name' key within the 'metadata' attribute
if link:
# Append each link in Markdown format for clickability
links.append(f"**Source {i}:** [{file_name}]({link})")

# Join the response with links, separating links by a new line
full_response = f"{response}\n\n**References:**\n" + "\n".join(links) if links else response

# Send the response back to the user
await cl.Message(content=full_response).send()

except Exception as e:
# Send the error message back to the user
await cl.Message(content=f"An error occurred: {str(e)}").send()
91 changes: 91 additions & 0 deletions project-UI/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from chainlit.utils import mount_chainlit

app = FastAPI()

# Mount static files directory
app.mount("/static", StaticFiles(directory="code/static"), name="static")

# Mount Chainlit app at /chainlit
mount_chainlit(app=app, target="code/chainlitmain.py", path="/chainlit")

# Serve the main webpage
@app.get("/", response_class=HTMLResponse)
async def get_homepage():
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>FastAPI with Chainlit</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
}
#chat-popup {
display: none;
position: fixed;
bottom: 80px;
right: 20px;
width: 400px;
height: 600px;
border: 2px solid #ccc;
background: #fff;
z-index: 1000;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
border-radius: 10px;
}
iframe {
width: 100%;
height: 100%;
border: none;
border-radius: 10px;
}
#chat-button {
position: fixed;
bottom: 20px;
right: 20px;
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1001;
}
#chat-button img {
width: 30px; /* Increased from 10px */
height: auto;
}
</style>
<script>
window.onload = function() {
var popup = document.getElementById("chat-popup");
popup.style.display = "none";
}

function toggleChat() {
var popup = document.getElementById("chat-popup");
var currentDisplay = window.getComputedStyle(popup).display;
popup.style.display = currentDisplay === "none" ? "block" : "none";
}
</script>
</head>
<body>
<h1>Welcome to Boston Public School Policy Chatbot</h1>
<div id="chat-button" onclick="toggleChat()" style="cursor: pointer;">
<img src="/static/images/chainlit.png" alt="Chat with Chainlit">
</div>
<div id="chat-popup">
<iframe src="/chainlit"></iframe>
</div>
</body>
</html>
"""
return HTMLResponse(content=html_content)