Skip to content

Commit

Permalink
Merge pull request #4 from sbslee/0.5.0-dev
Browse files Browse the repository at this point in the history
0.5.0 dev
  • Loading branch information
sbslee authored Jun 8, 2023
2 parents 0ea55f5 + 4523080 commit df705d4
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 0.5.0 (2023-06-08)
* Enable users to ask follow-up questions when chatting with documents.
* Enable users to customize chatbot parameters by uploading a configuration file.

## 0.4.0 (2023-06-02)
* Allow users to modify chatbot parameters (e.g. prompt, temperature, and chunk size).

Expand Down
Binary file modified images/chatgpt.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/docgpt.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 72 additions & 24 deletions kanu/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import configparser
import tkinter as tk
from tkinter import filedialog
import importlib.util

from .version import __version__
Expand All @@ -17,7 +19,7 @@ def __init__(self, root):
self.container = None
self.root = root
self.root.title(f"KANU ({__version__})")
self.root.geometry("600x500")
self.root.geometry("600x620")
self.homepage()

def homepage(self):
Expand All @@ -41,36 +43,56 @@ def config_chatgpt(self):
l = tk.Label(self.container, text="Required packages:")
l.grid(row=1, column=0, columnspan=2)
self.display_required_dependency(2, "openai")
m = tk.Message(self.container, width=300, text="Option 1. Upload a configuration file")
m.grid(row=3, column=0, columnspan=2)
b = tk.Button(self.container, text="Browse", command=self.parse_chatgpt_config)
b.grid(row=4, column=0)
b = tk.Button(self.container, text="Template", command=self.template_chatgpt_config)
b.grid(row=4, column=1)
m = tk.Message(self.container, width=300, text="Option 2. Configure manually")
m.grid(row=5, column=0, columnspan=2)
self.model = tk.StringVar(self.container, value="gpt-3.5-turbo")
l = tk.Label(self.container, text="Model:")
l.grid(row=3, column=0, columnspan=2)
l.grid(row=6, column=0, columnspan=2)
b = tk.Radiobutton(self.container, variable=self.model, text="gpt-3.5-turbo", value="gpt-3.5-turbo")
b.grid(row=4, column=0)
b.grid(row=7, column=0)
b = tk.Radiobutton(self.container, variable=self.model, text="gpt-4", value="gpt-4")
b.grid(row=4, column=1)
b.grid(row=7, column=1)
l = tk.Label(self.container, text="System message ⓘ:")
Tooltip(l, "The system message helps set the behavior of the chatbot.")
l.grid(row=5, column=0, columnspan=2)
l.grid(row=8, column=0, columnspan=2)
self.prompt = tk.Text(self.container, height=9, width=42)
sb = tk.Scrollbar(self.container, command=self.prompt.yview)
self.prompt.insert("1.0", CHATGPT_PROMPT)
self.prompt.grid(row=6, column=0, columnspan=2, sticky="nsew")
sb.grid(row=6, column=2, sticky="ns")
self.prompt.grid(row=9, column=0, columnspan=2, sticky="nsew")
sb.grid(row=9, column=2, sticky="ns")
self.prompt["yscrollcommand"] = sb.set
l = tk.Label(self.container, text="Temperature ⓘ:")
Tooltip(l, "The randomness in generating responses, which ranges between 0 and 1, with 0 indicating almost deterministic behavior.")
l.grid(row=7, column=0, columnspan=2)
l.grid(row=10, column=0, columnspan=2)
self.temperature = tk.DoubleVar(self.container, value=0.5)
e = tk.Entry(self.container, textvariable=self.temperature)
e.grid(row=8, column=0, columnspan=2)
e.grid(row=11, column=0, columnspan=2)
l = tk.Label(self.container, text="OpenAI API key:")
l.grid(row=9, column=0, columnspan=2)
l.grid(row=12, column=0, columnspan=2)
e = tk.Entry(self.container)
e.grid(row=10, column=0, columnspan=2)
e.grid(row=13, column=0, columnspan=2)
b = tk.Button(self.container, text="Submit", command=lambda: self.deploy_agent("ChatGPT", e.get(), self.model.get(), self.temperature.get(), self.prompt.get("1.0", "end-1c")))
b.grid(row=11, column=0)
b.grid(row=14, column=0)
b = tk.Button(self.container, text="Go back", command=lambda: self.homepage())
b.grid(row=11, column=1)
b.grid(row=14, column=1)

def parse_chatgpt_config(self):
config = configparser.ConfigParser()
config.read(filedialog.askopenfilename())
self.deploy_agent("ChatGPT", config["USER"]["openai_key"], config["DEFAULT"]["model"], float(config["DEFAULT"]["temperature"]), config["DEFAULT"]["prompt"])

def template_chatgpt_config(self):
config = configparser.ConfigParser()
config["DEFAULT"] = {"model": "gpt-3.5-turbo", "temperature": "0.5", "prompt": CHATGPT_PROMPT}
config["USER"] = {"openai_key": ""}
with open(filedialog.asksaveasfilename(), "w") as f:
config.write(f)

def config_docgpt(self):
self.container.pack_forget()
Expand All @@ -88,30 +110,56 @@ def config_docgpt(self):
self.display_optional_dependency(6, "pdfminer.six", "pdfminer", "Required for .pdf documents.")
self.display_optional_dependency(7, "unstructured", "unstructured", "Required for .doc and .docx documents.")
self.display_optional_dependency(8, "tabulate", "tabulate", "Required for .doc and .docx documents.")
m = tk.Message(self.container, width=300, text="Option 1. Upload a configuration file")
m.grid(row=9, column=0, columnspan=2)
b = tk.Button(self.container, text="Browse", command=self.parse_docgpt_config)
b.grid(row=10, column=0)
b = tk.Button(self.container, text="Template", command=self.template_docgpt_config)
b.grid(row=10, column=1)
m = tk.Message(self.container, width=300, text="Option 2. Configure manually")
m.grid(row=11, column=0, columnspan=2)
self.model = tk.StringVar(self.container, value="gpt-3.5-turbo")
l = tk.Label(self.container, text="Model:")
l.grid(row=9, column=0, columnspan=2)
l.grid(row=12, column=0, columnspan=2)
rb = tk.Radiobutton(self.container, variable=self.model, text="gpt-3.5-turbo", value="gpt-3.5-turbo")
rb.grid(row=10, column=0)
rb.grid(row=13, column=0)
rb = tk.Radiobutton(self.container, variable=self.model, text="gpt-4", value="gpt-4")
rb.grid(row=10, column=1)
rb.grid(row=13, column=1)
l = tk.Label(self.container, text="System message ⓘ:")
Tooltip(l, "The system message helps set the behavior of the chatbot.")
l.grid(row=11, column=0, columnspan=3)
l.grid(row=14, column=0, columnspan=2)
self.prompt = tk.Text(self.container, height=9, width=42)
sb = tk.Scrollbar(self.container, command=self.prompt.yview)
self.prompt.insert("1.0", DOCGPT_PROMPT)
self.prompt.grid(row=12, column=0, columnspan=3, sticky="nsew")
sb.grid(row=12, column=3, sticky="ns")
self.prompt.grid(row=15, column=0, columnspan=2, sticky="nsew")
sb.grid(row=15, column=2, sticky="ns")
self.prompt["yscrollcommand"] = sb.set
l = tk.Label(self.container, text="Temperature ⓘ:")
Tooltip(l, "The randomness in generating responses, which ranges between 0 and 1, with 0 indicating almost deterministic behavior.")
l.grid(row=16, column=0, columnspan=2)
self.temperature = tk.DoubleVar(self.container, value=0.5)
e = tk.Entry(self.container, textvariable=self.temperature)
e.grid(row=17, column=0, columnspan=2)
l = tk.Label(self.container, text="OpenAI API key:")
l.grid(row=13, column=0, columnspan=2)
l.grid(row=18, column=0, columnspan=2)
e = tk.Entry(self.container)
e.grid(row=14, column=0, columnspan=2)
b = tk.Button(self.container, text="Submit", command=lambda: self.deploy_agent("DocGPT", e.get(), self.model.get(), self.prompt.get("1.0", "end-1c")))
b.grid(row=15, column=0)
e.grid(row=19, column=0, columnspan=2)
b = tk.Button(self.container, text="Submit", command=lambda: self.deploy_agent("DocGPT", e.get(), self.model.get(), self.prompt.get("1.0", "end-1c"), self.temperature.get()))
b.grid(row=20, column=0)
b = tk.Button(self.container, text="Go back", command=lambda: self.homepage())
b.grid(row=15, column=1)
b.grid(row=20, column=1)

def parse_docgpt_config(self):
config = configparser.ConfigParser()
config.read(filedialog.askopenfilename())
self.deploy_agent("DocGPT", config["USER"]["openai_key"], config["DEFAULT"]["model"], float(config["DEFAULT"]["temperature"]), config["DEFAULT"]["prompt"])

def template_docgpt_config(self):
config = configparser.ConfigParser()
config["DEFAULT"] = {"model": "gpt-3.5-turbo", "temperature": "0.5", "prompt": DOCGPT_PROMPT}
config["USER"] = {"openai_key": ""}
with open(filedialog.asksaveasfilename(), "w") as f:
config.write(f)

def deploy_agent(self, agent, *args, **kwargs):
if agent == "ChatGPT":
Expand Down
30 changes: 18 additions & 12 deletions kanu/docgpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.chains import ConversationalRetrievalChain
from langchain.prompts import PromptTemplate
from langchain.memory import ConversationBufferMemory

from langchain.document_loaders import (
TextLoader,
Expand All @@ -18,15 +19,17 @@
from .utils import Tooltip

DOCUMENT_LOADERS = {
".txt": TextLoader,
".pdf": PDFMinerLoader,
".doc": UnstructuredWordDocumentLoader,
".docx": UnstructuredWordDocumentLoader,
".txt": (TextLoader, {"encoding": "utf8"}),
".pdf": (PDFMinerLoader, {}),
".doc": (UnstructuredWordDocumentLoader, {}),
".docx": (UnstructuredWordDocumentLoader, {}),
}

class DocGPT:
def __init__(self, kanu, openai_key, model, prompt):
def __init__(self, kanu, openai_key, model, temperature, prompt):
self.kanu = kanu
self.model = model
self.temperature = temperature
self.prompt = prompt
os.environ["OPENAI_API_KEY"] = openai_key

Expand Down Expand Up @@ -85,12 +88,14 @@ def run(self):
self.option2_button["state"] = tk.DISABLED

def query(self):
self.memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
self.db = Chroma(persist_directory=self.database_directory, embedding_function=OpenAIEmbeddings())
self.qa = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model_name=self.model),
chain_type="stuff",
self.qa = ConversationalRetrievalChain.from_llm(
llm=ChatOpenAI(model_name=self.model, temperature=self.temperature),
retriever=self.db.as_retriever(),
chain_type_kwargs={"prompt": PromptTemplate(template=self.prompt, input_variables=["context", "question"])}
memory=self.memory,
chain_type="stuff",
combine_docs_chain_kwargs={"prompt": PromptTemplate(template=self.prompt, input_variables=["context", "question"])}
)
self.kanu.container.pack_forget()
self.kanu.container = tk.Frame(self.kanu.root)
Expand All @@ -110,7 +115,7 @@ def query(self):

def send_message(self, entry):
self.session.insert(tk.END, "You: " + entry.get() + "\n")
response = self.qa(entry.get())["result"]
response = self.qa(entry.get())["answer"]
self.session.insert(tk.END, "Bot: " + response + "\n")
entry.delete(0, tk.END)

Expand All @@ -122,7 +127,8 @@ def go_with_option1(self):
file_ext = os.path.splitext(file_path)[1]
if file_ext not in DOCUMENT_LOADERS:
continue
loader = DOCUMENT_LOADERS[file_ext](file_path)
loader_class, loader_kwargs = DOCUMENT_LOADERS[file_ext]
loader = loader_class(file_path, **loader_kwargs)
document = loader.load()[0]
documents.append(document)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=self.chunk_size.get(), chunk_overlap=self.chunk_overlap.get())
Expand Down
2 changes: 1 addition & 1 deletion kanu/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.4.0"
__version__ = "0.5.0"

0 comments on commit df705d4

Please sign in to comment.