Skip to content

Commit

Permalink
Chatbot sources response from file
Browse files Browse the repository at this point in the history
  • Loading branch information
nicole-brewer committed Apr 5, 2024
1 parent 721dc3f commit 7c9b18a
Show file tree
Hide file tree
Showing 12 changed files with 518 additions and 328 deletions.
32 changes: 19 additions & 13 deletions jupyter_mentor/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,25 @@
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotModel.prompt': ( 'chatbot.html#chatbotmodel.prompt',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotModel.prompt_course_files': ( 'chatbot.html#chatbotmodel.prompt_course_files',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotModel.prompt_with_template': ( 'chatbot.html#chatbotmodel.prompt_with_template',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotModel.update_bot_template': ( 'chatbot.html#chatbotmodel.update_bot_template',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotModel.update_human_template': ( 'chatbot.html#chatbotmodel.update_human_template',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotView': ('chatbot.html#chatbotview', 'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.ChatBotView.__init__': ( 'chatbot.html#chatbotview.__init__',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.EducatorChatBot': ( 'chatbot.html#educatorchatbot',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.EducatorChatBot.__init__': ( 'chatbot.html#educatorchatbot.__init__',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.StudentChatBot': ( 'chatbot.html#studentchatbot',
'jupyter_mentor/chatbot.py'),
'jupyter_mentor.chatbot.StudentChatBot.__init__': ( 'chatbot.html#studentchatbot.__init__',
'jupyter_mentor/chatbot.py')},
'jupyter_mentor/chatbot.py')},
'jupyter_mentor.chatbot_tab': { 'jupyter_mentor.chatbot_tab.EducatorChatBot': ( 'chatbot.html#educatorchatbot',
'jupyter_mentor/chatbot_tab.py'),
'jupyter_mentor.chatbot_tab.EducatorChatBot.__init__': ( 'chatbot.html#educatorchatbot.__init__',
'jupyter_mentor/chatbot_tab.py'),
'jupyter_mentor.chatbot_tab.StudentChatBot': ( 'chatbot.html#studentchatbot',
'jupyter_mentor/chatbot_tab.py'),
'jupyter_mentor.chatbot_tab.StudentChatBot.__init__': ( 'chatbot.html#studentchatbot.__init__',
'jupyter_mentor/chatbot_tab.py')},
'jupyter_mentor.educator_course_overview': { 'jupyter_mentor.educator_course_overview.EducatorCourseOverview': ( 'educator_course_overview.html#educatorcourseoverview',
'jupyter_mentor/educator_course_overview.py'),
'jupyter_mentor.educator_course_overview.EducatorCourseOverview.__init__': ( 'educator_course_overview.html#educatorcourseoverview.__init__',
Expand All @@ -50,10 +54,12 @@
'jupyter_mentor/file_viewer.py')},
'jupyter_mentor.llm': { 'jupyter_mentor.llm.FileModel': ('llm.html#filemodel', 'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.__init__': ('llm.html#filemodel.__init__', 'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.load_markdown': ( 'llm.html#filemodel.load_markdown',
'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.load_pdf': ('llm.html#filemodel.load_pdf', 'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.load_text': ('llm.html#filemodel.load_text', 'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.load_markdown_to_db': ( 'llm.html#filemodel.load_markdown_to_db',
'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.load_pdf_to_db': ( 'llm.html#filemodel.load_pdf_to_db',
'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.load_text_to_db': ( 'llm.html#filemodel.load_text_to_db',
'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.FileModel.save_content_from_upload': ( 'llm.html#filemodel.save_content_from_upload',
'jupyter_mentor/llm.py'),
'jupyter_mentor.llm.LLM': ('llm.html#llm', 'jupyter_mentor/llm.py'),
Expand Down
114 changes: 29 additions & 85 deletions jupyter_mentor/chatbot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/06_chatbot.ipynb.
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_chatbot.ipynb.

# %% auto 0
__all__ = ['ChatBotModel', 'ChatBotView', 'ChatBot', 'StudentChatBot', 'EducatorChatBot']
__all__ = ['ChatBotModel', 'ChatBotView', 'ChatBot']

# %% ../nbs/06_chatbot.ipynb 1
# %% ../nbs/04_chatbot.ipynb 1
import ipywidgets as widgets
import traitlets
from ipywidgets import Textarea, Text, Layout, HBox, Stack, Layout
Expand All @@ -17,13 +17,13 @@
SystemMessagePromptTemplate,
)
from langchain_openai import ChatOpenAI
from .llm import FileModel

# %% ../nbs/06_chatbot.ipynb 5
class ChatBotModel(HasTraits):
# %% ../nbs/04_chatbot.ipynb 2
class ChatBotModel(FileModel):

def __init__(self, llm, bot_template="You are playing the role of a tutor/educator", human_template="{input_text}"):
def __init__(self, bot_template="You are playing the role of a tutor/educator", human_template="{input_text}"):
super().__init__()
self.llm = llm
self.human_template = human_template
self.human_message_prompt = HumanMessagePromptTemplate.from_template(self.human_template)
self.update_bot_template(bot_template)
Expand All @@ -37,13 +37,29 @@ def update_human_template(self, human_template):
self.human_template = human_template
self.human_message_prompt = HumanMessagePromptTemplate.from_template(self.human_template)
self.chat_prompt = ChatPromptTemplate.from_messages([self.bot_message_prompt, self.human_message_prompt])

def prompt(self, kwargs):

def prompt(self, input_text):
ret = self.llm.invoke(input_text)
return ret.content

def prompt_with_template(self, kwargs):
ret = self.llm.invoke(self.chat_prompt.format_prompt(**kwargs))
#ret = self.llm.invoke(self.chat_prompt.format_prompt(input_text=input_text))
return ret.content

# %% ../nbs/06_chatbot.ipynb 8
def prompt_course_files(self, input_text, k = 4):
if self.db:
try:
docs = self.db.similarity_search(input_text, k=1)
docs_content = " ".join([d.page_content for d in docs])
self.update_bot_template("You are an educator/tutor. Answer the question based on the following information: {docs}")
ret = self.llm.invoke(self.chat_prompt.format_prompt(docs=docs, input_text=input_text))
return "\n\n".join([ret.content + '\n\nSourced from ' + docs[0].metadata['source'] + ': \n', docs_content])
except Exception as e:
return docs[0].page_content
else:
return self.prompt(input_text)

# %% ../nbs/04_chatbot.ipynb 6
class ChatBotView(widgets.VBox):

def __init__(self):
Expand All @@ -70,7 +86,7 @@ def __init__(self):

self.children = (self.chat, self.user_input_and_submit)

# %% ../nbs/06_chatbot.ipynb 10
# %% ../nbs/04_chatbot.ipynb 8
class ChatBot(ChatBotView):

def __init__(self, model):
Expand All @@ -83,77 +99,5 @@ def __init__(self, model):
def on_click(self, change):
self.chat.value = self.chat.value + "USER: " + self.user_input.value + '\n\n'
self.user_input.value = ''
ret = self.model.prompt(self.user_input.value)
ret = self.model.prompt_course_files(self.user_input.value)
self.chat.value = self.chat.value + "CHATBOT: " + ret + '\n\n'

# %% ../nbs/06_chatbot.ipynb 12
class StudentChatBot(widgets.VBox):

#user = traitlets.CUnicode()
#response = traitlets.CUnicode()
#step_by_step = traitlets.Bool()
#metaphor = traitlets.Bool()
#hints = traitlets.Bool()
#guided_questions = traitlets.Bool()

def __init__(self, chatbot_model):
# If you forget to call the superconstructor on an extended widget
# you will get an AttributeError: object has no attribute '_model_id'
super().__init__()

self.chat_bot = ChatBot(chatbot_model)

self.suggestion_buttons = HBox()
self.step_by_step = widgets.Button(
description='Step-by-Step',
button_style='info',
tooltip='Description',
)
self.metaphor = widgets.Button(
description='Metaphor',
button_style='info',
tooltip='Description',
)
self.hints = widgets.Button(
description='Hints',
button_style='info',
tooltip='Description',
)
self.guided_questions = widgets.Button(
description='AI Guided Questions',
button_style='info',
tooltip='Description',
)
self.suggestion_buttons.children = (self.step_by_step, self.metaphor, self.hints, self.guided_questions)
self.children = (self.chat_bot, self.suggestion_buttons)

# %% ../nbs/06_chatbot.ipynb 14
class EducatorChatBot(widgets.VBox):

#user = traitlets.CUnicode()
#response = traitlets.CUnicode()
#step_by_step = traitlets.Bool()
#metaphor = traitlets.Bool()
#hints = traitlets.Bool()
#guided_questions = traitlets.Bool()

def __init__(self, chatbot_model):
# If you forget to call the superconstructor on an extended widget
# you will get an AttributeError: object has no attribute '_model_id'
super().__init__()

self.chat_bot = ChatBot(chatbot_model)

self.suggestion_buttons = HBox()
self.exam_questions = widgets.Button(
description='Exam Questions',
button_style='info',
tooltip='Description',
)
self.lesson_plan = widgets.Button(
description='Lesson Plan',
button_style='info',
tooltip='Description',
)
self.suggestion_buttons.children = (self.exam_questions, self.lesson_plan )
self.children = (self.chat_bot, self.suggestion_buttons)
92 changes: 92 additions & 0 deletions jupyter_mentor/chatbot_tab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/06_chatbot.ipynb.

# %% auto 0
__all__ = ['StudentChatBot', 'EducatorChatBot']

# %% ../nbs/06_chatbot.ipynb 1
import ipywidgets as widgets
import traitlets
from ipywidgets import Textarea, Text, Layout, HBox, Stack, Layout
from traitlets import HasTraits
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.prompts.chat import (
ChatPromptTemplate,
HumanMessagePromptTemplate,
SystemMessagePromptTemplate,
)
from langchain_openai import ChatOpenAI
from .chatbot import ChatBot, ChatBotModel

# %% ../nbs/06_chatbot.ipynb 7
class StudentChatBot(widgets.VBox):

#user = traitlets.CUnicode()
#response = traitlets.CUnicode()
#step_by_step = traitlets.Bool()
#metaphor = traitlets.Bool()
#hints = traitlets.Bool()
#guided_questions = traitlets.Bool()

def __init__(self, chatbot_model):
# If you forget to call the superconstructor on an extended widget
# you will get an AttributeError: object has no attribute '_model_id'
super().__init__()

self.chat_bot = ChatBot(chatbot_model)

self.suggestion_buttons = HBox()
self.step_by_step = widgets.Button(
description='Step-by-Step',
button_style='info',
tooltip='Description',
)
self.metaphor = widgets.Button(
description='Metaphor',
button_style='info',
tooltip='Description',
)
self.hints = widgets.Button(
description='Hints',
button_style='info',
tooltip='Description',
)
self.guided_questions = widgets.Button(
description='AI Guided Questions',
button_style='info',
tooltip='Description',
)
self.suggestion_buttons.children = (self.step_by_step, self.metaphor, self.hints, self.guided_questions)
self.children = (self.chat_bot, self.suggestion_buttons)

# %% ../nbs/06_chatbot.ipynb 9
class EducatorChatBot(widgets.VBox):

#user = traitlets.CUnicode()
#response = traitlets.CUnicode()
#step_by_step = traitlets.Bool()
#metaphor = traitlets.Bool()
#hints = traitlets.Bool()
#guided_questions = traitlets.Bool()

def __init__(self, chatbot_model):
# If you forget to call the superconstructor on an extended widget
# you will get an AttributeError: object has no attribute '_model_id'
super().__init__()

self.chat_bot = ChatBot(chatbot_model)

self.suggestion_buttons = HBox()
self.exam_questions = widgets.Button(
description='Exam Questions',
button_style='info',
tooltip='Description',
)
self.lesson_plan = widgets.Button(
description='Lesson Plan',
button_style='info',
tooltip='Description',
)
self.suggestion_buttons.children = (self.exam_questions, self.lesson_plan )
self.children = (self.chat_bot, self.suggestion_buttons)
44 changes: 28 additions & 16 deletions jupyter_mentor/llm.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_llm.ipynb.
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_llm.ipynb.

# %% auto 0
__all__ = ['LLM', 'FileModel']

# %% ../nbs/01_llm.ipynb 1
from traitlets import HasTraits, Unicode
# %% ../nbs/02_llm.ipynb 1
from traitlets import HasTraits, Unicode, List
from langchain_openai import ChatOpenAI
import os
from langchain.docstore.document import Document
Expand All @@ -14,7 +14,7 @@
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

# %% ../nbs/01_llm.ipynb 2
# %% ../nbs/02_llm.ipynb 2
class LLM(HasTraits):

def __init__(self, filepath='OPENAI_API_KEY'):
Expand All @@ -25,38 +25,50 @@ def __init__(self, filepath='OPENAI_API_KEY'):
os.environ['OPENAI_API_KEY'] = openai_api_key
self.llm = ChatOpenAI(model_name="gpt-3.5-turbo")

# %% ../nbs/01_llm.ipynb 4
# %% ../nbs/02_llm.ipynb 4
class FileModel(LLM):
# Define a Unicode string trait
select = Unicode()
files = List()

def __init__(self):
def __init__(self, course_file_dir = 'course_files/'):
super().__init__()
#self.embeddings = OpenAIEmbeddings()
#doc = Document(page_content='Course')
#self.db = FAISS.from_documents(doc, self.embeddings)
self.course_file_dir = course_file_dir
self.embeddings = OpenAIEmbeddings()
self.db = None

def save_content_from_upload(values):
for value in values:
with open('course_files/' + value['name'], "wb") as fp:
with open(filepath + value['name'], "wb") as fp:
fp.write(value['content'])

def load_text(self, text):
def load_text_to_db(self, text):
doc = Document(page_content=text)
db = FAISS.from_documents(doc, self.embeddings)
self.db.merge_from(db)
if self.db:
self.db.merge_from(db)
else:
self.db = db

def load_pdf(self, filepath):
def load_pdf_to_db(self, filepath):
loader = PyPDFLoader(filepath)
pages = loader.load_and_split()
db = FAISS.from_documents(pages, self.embeddings)
self.db.merge_from(db)
if self.db:
self.db.merge_from(db)
else:
self.db = db
self.files.append(filepath)

def load_markdown(filepath):
def load_markdown_to_db(filepath):
loader = UnstructuredMarkdownLoader(filepath, mode="elements") #mode=elements breaks up the text into chunks
doc = loader.load()
db = FAISS.from_documents(doc, embeddings)
self.db.merge_from(db)
if self.db:
self.db.merge_from(db)
else:
self.db = db
self.files.append(filepath)

def save_content_from_upload(values):
for value in values:
Expand Down
2 changes: 0 additions & 2 deletions jupyter_mentor/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from IPython.display import display, clear_output
import ipyvuetify as v


# %% ../nbs/01_login.ipynb 3
class Login(VBox):

Expand Down Expand Up @@ -38,4 +37,3 @@ def __init__(self):
self.key_box, # Password label and input box
HBox([self.login_button], layout={'justify_content': 'flex-end'}), # Login button aligned to the right
]

Loading

0 comments on commit 7c9b18a

Please sign in to comment.