Skip to content

Commit

Permalink
Merge pull request #3 from sbslee/0.4.0-dev
Browse files Browse the repository at this point in the history
0.4.0 dev
  • Loading branch information
sbslee authored Jun 2, 2023
2 parents 69d35ab + 5d64fe1 commit 0ea55f5
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 36 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# CHANGELOG

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

## 0.3.0 (2023-05-30)
* Add multi-document chat functionality.
* Add chat functionality for additional document formats (.pdf, .doc, and .docx).

## 0.2.0 (2023-03-27)
## 0.2.0 (2023-05-27)
* Enable users to initiate a new chat session.
* Enable users to choose their preferred GPT model.
* Enable users to chat with their text (.txt) documents.

## 0.1.0 (2023-03-24)
## 0.1.0 (2023-05-24)
* Initial release.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# README

[![PyPI](https://badge.fury.io/py/kanu.svg)](https://badge.fury.io/py/kanu)

KANU is a minimalistic Python-based GUI for various chatbots.

## Chatbots
Expand All @@ -26,4 +28,4 @@ $ kanu

## Changelog

See the [CHANGELOG.md](./CHANGELOG.md) file for details.
See the [CHANGELOG.md](https://github.com/sbslee/kanu/blob/main/CHANGELOG.md) file for details.
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.
62 changes: 47 additions & 15 deletions kanu/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@
from .version import __version__
from .utils import Tooltip

CHATGPT_PROMPT = """You are a helpful assistant."""
DOCGPT_PROMPT = """Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
{context}
Question: {question}
Helpful Answer:"""

class KANU:
def __init__(self, root):
self.container = None
self.root = root
self.root.title(f"KANU ({__version__})")
self.root.geometry("600x400")
self.root.geometry("600x500")
self.homepage()

def homepage(self):
Expand Down Expand Up @@ -40,14 +48,29 @@ def config_chatgpt(self):
b.grid(row=4, column=0)
b = tk.Radiobutton(self.container, variable=self.model, text="gpt-4", value="gpt-4")
b.grid(row=4, column=1)
l = tk.Label(self.container, text="OpenAI API key:")
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)
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["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)
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)
l = tk.Label(self.container, text="OpenAI API key:")
l.grid(row=9, column=0, columnspan=2)
e = tk.Entry(self.container)
e.grid(row=6, column=0, columnspan=2)
b = tk.Button(self.container, text="Submit", command=lambda: self.deploy_agent("ChatGPT", e.get(), self.model.get()))
b.grid(row=7, column=0)
e.grid(row=10, 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 = tk.Button(self.container, text="Go back", command=lambda: self.homepage())
b.grid(row=7, column=1)
b.grid(row=11, column=1)

def config_docgpt(self):
self.container.pack_forget()
Expand All @@ -68,18 +91,27 @@ def config_docgpt(self):
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)
b = tk.Radiobutton(self.container, variable=self.model, text="gpt-3.5-turbo", value="gpt-3.5-turbo")
b.grid(row=10, column=0)
b = tk.Radiobutton(self.container, variable=self.model, text="gpt-4", value="gpt-4")
b.grid(row=10, column=1)
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 = tk.Radiobutton(self.container, variable=self.model, text="gpt-4", value="gpt-4")
rb.grid(row=10, 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)
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["yscrollcommand"] = sb.set
l = tk.Label(self.container, text="OpenAI API key:")
l.grid(row=11, column=0, columnspan=2)
l.grid(row=13, column=0, columnspan=2)
e = tk.Entry(self.container)
e.grid(row=12, column=0, columnspan=2)
b = tk.Button(self.container, text="Submit", command=lambda: self.deploy_agent("DocGPT", e.get(), self.model.get()))
b.grid(row=13, column=0)
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)
b = tk.Button(self.container, text="Go back", command=lambda: self.homepage())
b.grid(row=13, column=1)
b.grid(row=15, column=1)

def deploy_agent(self, agent, *args, **kwargs):
if agent == "ChatGPT":
Expand Down
7 changes: 5 additions & 2 deletions kanu/chatgpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import openai

class ChatGPT:
def __init__(self, kanu, openai_key, model):
def __init__(self, kanu, openai_key, model, temperature, prompt):
self.kanu = kanu
self.model = model
self.temperature = temperature
self.prompt = prompt
openai.api_key = openai_key

def run(self):
Expand All @@ -28,11 +30,12 @@ def run(self):

def send_message(self, entry):
if not self.messages:
self.messages.append({"role": "system", "content": "You are a helpful assistant."})
self.messages.append({"role": "system", "content": self.prompt})
self.messages += [{"role": "user", "content": entry.get()}]
bot_response = openai.ChatCompletion.create(
model=self.model,
messages=self.messages,
temperature=self.temperature,
)
response = bot_response["choices"][0]["message"]["content"]
self.messages += [{"role": "assistant", "content": response}]
Expand Down
44 changes: 31 additions & 13 deletions kanu/docgpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

from langchain.document_loaders import (
TextLoader,
Expand All @@ -22,11 +23,11 @@
".doc": UnstructuredWordDocumentLoader,
".docx": UnstructuredWordDocumentLoader,
}

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

def run(self):
Expand All @@ -39,8 +40,8 @@ def run(self):
b.grid(row=1, column=0)
b = tk.Button(self.kanu.container, text="Reload", command=lambda: self.run())
b.grid(row=1, column=2)
l = tk.Message(self.kanu.container, width=300, text="Option 1. Create a new database")
l.grid(row=2, column=0, columnspan=3)
m = tk.Message(self.kanu.container, width=300, text="Option 1. Create a new database")
m.grid(row=2, column=0, columnspan=3)
l = tk.Label(self.kanu.container, text="Document ⓘ:")
Tooltip(l, "Directory containing documents for the database.")
l.grid(row=3, column=0)
Expand All @@ -55,25 +56,42 @@ def run(self):
self.new_database_label.grid(row=4, column=1)
b = tk.Button(self.kanu.container, text="Browse", command=self.specify_new_database_directory)
b.grid(row=4, column=2)
l = tk.Label(self.kanu.container, text="Chunk size ⓘ:")
Tooltip(l, "The maximum number of characters in each chunk.")
l.grid(row=5, column=0)
self.chunk_size = tk.IntVar(self.kanu.container, value=1000)
e = tk.Entry(self.kanu.container, textvariable=self.chunk_size)
e.grid(row=5, column=1, columnspan=2)
l = tk.Label(self.kanu.container, text="Chunk overlap ⓘ:")
Tooltip(l, "The number of overlapping characters between adjacent chunks.")
l.grid(row=6, column=0)
self.chunk_overlap = tk.IntVar(self.kanu.container, value=50)
e = tk.Entry(self.kanu.container, textvariable=self.chunk_overlap)
e.grid(row=6, column=1, columnspan=2)
self.option1_button = tk.Button(self.kanu.container, text="Go with Option 1", command=self.go_with_option1)
self.option1_button.grid(row=5, column=0, columnspan=3)
self.option1_button.grid(row=7, column=0, columnspan=3)
self.option1_button["state"] = tk.DISABLED
l = tk.Message(self.kanu.container, width=300, text="Option 2. Use an existing database")
l.grid(row=6, column=0, columnspan=3)
m = tk.Message(self.kanu.container, width=300, text="Option 2. Use an existing database")
m.grid(row=8, column=0, columnspan=3)
l = tk.Label(self.kanu.container, text="Database ⓘ:")
Tooltip(l, "Directory where the database is stored.")
l.grid(row=7, column=0)
l.grid(row=9, column=0)
self.old_database_label = tk.Label(self.kanu.container, text="Not selected", fg="red")
self.old_database_label.grid(row=7, column=1)
self.old_database_label.grid(row=9, column=1)
b = tk.Button(self.kanu.container, text="Browse", command=self.specify_old_database_directory)
b.grid(row=7, column=2)
b.grid(row=9, column=2)
self.option2_button = tk.Button(self.kanu.container, text="Go with Option 2", command=self.go_with_option2)
self.option2_button.grid(row=8, column=0, columnspan=3)
self.option2_button.grid(row=10, column=0, columnspan=3)
self.option2_button["state"] = tk.DISABLED

def query(self):
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", retriever=self.db.as_retriever())
self.qa = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model_name=self.model),
chain_type="stuff",
retriever=self.db.as_retriever(),
chain_type_kwargs={"prompt": PromptTemplate(template=self.prompt, input_variables=["context", "question"])}
)
self.kanu.container.pack_forget()
self.kanu.container = tk.Frame(self.kanu.root)
self.kanu.container.pack()
Expand Down Expand Up @@ -107,7 +125,7 @@ def go_with_option1(self):
loader = DOCUMENT_LOADERS[file_ext](file_path)
document = loader.load()[0]
documents.append(document)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=50)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=self.chunk_size.get(), chunk_overlap=self.chunk_overlap.get())
texts = text_splitter.split_documents(documents)
db = Chroma.from_documents(texts, OpenAIEmbeddings(), persist_directory=self.database_directory)
db.add_documents(texts)
Expand Down
2 changes: 1 addition & 1 deletion kanu/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def show_tooltip(self, event):
self.tooltip = tk.Toplevel(self.widget)
self.tooltip.wm_overrideredirect(True)
self.tooltip.wm_geometry(f"+{x}+{y}")
l = tk.Label(self.tooltip, text=self.text, background="#ffffe0", relief="solid", borderwidth=1)
l = tk.Label(self.tooltip, text=self.text, background="#ffffe0", relief="solid", borderwidth=1, wraplength=400)
l.pack()

def hide_tooltip(self, event):
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.3.0"
__version__ = "0.4.0"

0 comments on commit 0ea55f5

Please sign in to comment.