from openai import OpenAI
import streamlit as st
import streamlit.components.v1 as components
import datetime
## Firestore ??
import os
import sys
import inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
import db_firestore as db
## ----------------------------------------------------------------
## LLM Part
import openai
from langchain_openai import ChatOpenAI, OpenAI, OpenAIEmbeddings
import tiktoken
from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from operator import itemgetter
from langchain.schema import StrOutputParser
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
import langchain_community.embeddings.huggingface
from langchain_community.embeddings.huggingface import HuggingFaceBgeEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import LLMChain
from langchain.chains.conversation.memory import ConversationBufferWindowMemory #, ConversationBufferMemory, ConversationSummaryMemory, ConversationSummaryBufferMemory
import os, dotenv
from dotenv import load_dotenv
load_dotenv()
if not os.path.isdir("../.streamlit"):
os.mkdir("../.streamlit")
print('made streamlit folder')
if not os.path.isfile("../.streamlit/secrets.toml"):
with open("../.streamlit/secrets.toml", "w") as f:
f.write(os.environ.get("STREAMLIT_SECRETS"))
print('made new file')
import db_firestore as db
## Load from streamlit!!
os.environ["HF_TOKEN"] = os.environ.get("HF_TOKEN") or st.secrets["HF_TOKEN"]
os.environ["OPENAI_API_KEY"] = os.environ.get("OPENAI_API_KEY") or st.secrets["OPENAI_API_KEY"]
os.environ["FIREBASE_CREDENTIAL"] = os.environ.get("FIREBASE_CREDENTIAL") or st.secrets["FIREBASE_CREDENTIAL"]
st.title("UAT for PatientLLM and GraderLLM")
## Hardcode indexes for now,
indexes = """Bleeding
ChestPain
Dysphagia
Headache
ShortnessOfBreath
Vomiting
Warfarin
Weakness
Weakness2""".split("\n")
if "selected_index" not in st.session_state:
st.session_state.selected_index = 3
if "index_selectbox" not in st.session_state:
st.session_state.index_selectbox = "Headache"
index_selectbox = st.selectbox("Select index",indexes, index=int(st.session_state.selected_index))
if index_selectbox != indexes[st.session_state.selected_index]:
st.session_state.selected_index = indexes.index(index_selectbox)
st.session_state.index_selectbox = index_selectbox
del st.session_state["store"]
del st.session_state["store2"]
del st.session_state["retriever"]
del st.session_state["retriever2"]
del st.session_state["chain"]
del st.session_state["chain2"]
if "openai_model" not in st.session_state:
st.session_state["openai_model"] = "gpt-3.5-turbo"
if "messages_1" not in st.session_state:
st.session_state.messages_1 = []
if "messages_2" not in st.session_state:
st.session_state.messages_2 = []
# if "start_time" not in st.session_state:
# st.session_state.start_time = None
if "active_chat" not in st.session_state:
st.session_state.active_chat = 1
model_name = "bge-large-en-v1.5"
model_kwargs = {"device": "cpu"}
# model_kwargs = {"device": "cuda"}
encode_kwargs = {"normalize_embeddings": True}
if "embeddings" not in st.session_state:
st.session_state.embeddings = HuggingFaceBgeEmbeddings(
# model_name=model_name,
model_kwargs = model_kwargs,
encode_kwargs = encode_kwargs)
embeddings = st.session_state.embeddings
if "llm" not in st.session_state:
st.session_state.llm = ChatOpenAI(model_name="gpt-3.5-turbo-1106", temperature=0)
llm = st.session_state.llm
if "llm_i" not in st.session_state:
st.session_state.llm_i = OpenAI(model_name="gpt-3.5-turbo-instruct", temperature=0)
llm_i = st.session_state.llm_i
if "llm_gpt4" not in st.session_state:
st.session_state.llm_gpt4 = ChatOpenAI(model_name="gpt-4-1106-preview", temperature=0)
llm_gpt4 = st.session_state.llm_gpt4
## ------------------------------------------------------------------------------------------------
## Patient part
index_name = f"indexes/{st.session_state.index_selectbox}/QA"
if "store" not in st.session_state:
st.session_state.store = db.get_store(index_name, embeddings=embeddings)
store = st.session_state.store
if "TEMPLATE" not in st.session_state:
with open('templates/patient.txt', 'r') as file:
TEMPLATE = file.read()
st.session_state.TEMPLATE = TEMPLATE
with st.expander("Patient Prompt"):
TEMPLATE = st.text_area("Patient Prompt", value=st.session_state.TEMPLATE)
prompt = PromptTemplate(
input_variables = ["question", "context"],
template = TEMPLATE
)
if "retriever" not in st.session_state:
st.session_state.retriever = store.as_retriever(search_type="similarity", search_kwargs={"k":2})
retriever = st.session_state.retriever
def format_docs(docs):
return "\n--------------------\n".join(doc.page_content for doc in docs)
if "memory" not in st.session_state:
st.session_state.memory = ConversationBufferWindowMemory(
llm=llm, memory_key="chat_history", input_key="question",
k=5, human_prefix="student", ai_prefix="patient",)
memory = st.session_state.memory
if ("chain" not in st.session_state
or
st.session_state.TEMPLATE != TEMPLATE):
st.session_state.chain = (
{
"context": retriever | format_docs,
"question": RunnablePassthrough()
} |
LLMChain(llm=llm, prompt=prompt, memory=memory, verbose=False)
)
chain = st.session_state.chain
sp_mapper = {"human":"student","ai":"patient"}
## ------------------------------------------------------------------------------------------------
## ------------------------------------------------------------------------------------------------
## Grader part
index_name = f"indexes/{st.session_state.index_selectbox}/Rubric"
if "store2" not in st.session_state:
st.session_state.store2 = db.get_store(index_name, embeddings=embeddings)
store2 = st.session_state.store2
if "TEMPLATE2" not in st.session_state:
with open('templates/grader.txt', 'r') as file:
TEMPLATE2 = file.read()
st.session_state.TEMPLATE2 = TEMPLATE2
with st.expander("Grader Prompt"):
TEMPLATE2 = st.text_area("Grader Prompt", value=st.session_state.TEMPLATE2)
prompt2 = PromptTemplate(
input_variables = ["question", "context", "history"],
template = TEMPLATE2
)
if "retriever2" not in st.session_state:
st.session_state.retriever2 = store2.as_retriever(search_type="similarity", search_kwargs={"k":2})
retriever2 = st.session_state.retriever2
def format_docs(docs):
return "\n--------------------\n".join(doc.page_content for doc in docs)
fake_history = '\n'.join([(sp_mapper.get(i.type, i.type) + ": "+ i.content) for i in memory.chat_memory.messages])
def x(_):
return fake_history
if ("chain2" not in st.session_state
or
st.session_state.TEMPLATE2 != TEMPLATE2):
st.session_state.chain2 = (
{
"context": retriever | format_docs,
"history": x,
"question": RunnablePassthrough(),
} |
# LLMChain(llm=llm_i, prompt=prompt2, verbose=False ) #|
LLMChain(llm=llm_i, prompt=prompt2, verbose=False ) #|
| {
"json": itemgetter("text"),
"text": (
LLMChain(
llm=llm,
prompt=PromptTemplate(
input_variables=["text"],
template="Interpret the following JSON of the student's grades, and do a write-up for each section.\n\n```json\n{text}\n```"),
verbose=False)
)
}
)
chain2 = st.session_state.chain2
## ------------------------------------------------------------------------------------------------
## ------------------------------------------------------------------------------------------------
## Streamlit now
# from dotenv import load_dotenv
# import os
# load_dotenv()
# key = os.environ.get("OPENAI_API_KEY")
# client = OpenAI(api_key=key)
if st.button("Clear History and Memory", type="primary"):
st.session_state.messages_1 = []
st.session_state.messages_2 = []
st.session_state.memory = ConversationBufferWindowMemory(llm=llm, memory_key="chat_history", input_key="question" )
memory = st.session_state.memory
## Testing HTML
# html_string = """
#
#
#
# """
# components.html(html_string,
# width=1280,
# height=640)
st.write("Timer has been removed, switch with this button")
if st.button(f"Switch to {'PATIENT' if st.session_state.active_chat==2 else 'GRADER'}"+".... Buggy button, please double click"):
st.session_state.active_chat = 3 - st.session_state.active_chat
# st.write("Currently in " + ('PATIENT' if st.session_state.active_chat==2 else 'GRADER'))
# Create two columns for the two chat interfaces
col1, col2 = st.columns(2)
# First chat interface
with col1:
st.subheader("Student LLM")
for message in st.session_state.messages_1:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Second chat interface
with col2:
# st.write("pls dun spam this, its tons of tokens cos chat history")
st.subheader("Grader LLM")
st.write("grader takes a while to load... please be patient")
for message in st.session_state.messages_2:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Timer and Input
# time_left = None
# if st.session_state.start_time:
# time_elapsed = datetime.datetime.now() - st.session_state.start_time
# time_left = datetime.timedelta(minutes=10) - time_elapsed
# st.write(f"Time left: {time_left}")
# if time_left is None or time_left > datetime.timedelta(0):
# # Chat 1 is active
# prompt = st.text_input("Enter your message for Chat 1:")
# active_chat = 1
# messages = st.session_state.messages_1
# elif time_left and time_left <= datetime.timedelta(0):
# # Chat 2 is active
# prompt = st.text_input("Enter your message for Chat 2:")
# active_chat = 2
# messages = st.session_state.messages_2
if st.session_state.active_chat==1:
text_prompt = st.text_input("Enter your message for PATIENT")
messages = st.session_state.messages_1
else:
text_prompt = st.text_input("Enter your message for GRADER")
messages = st.session_state.messages_2
if text_prompt:
messages.append({"role": "user", "content": text_prompt})
with (col1 if st.session_state.active_chat == 1 else col2):
with st.chat_message("user"):
st.markdown(text_prompt)
with (col1 if st.session_state.active_chat == 1 else col2):
with st.chat_message("assistant"):
message_placeholder = st.empty()
if st.session_state.active_chat==1:
full_response = chain.invoke(text_prompt).get("text")
else:
full_response = chain2.invoke(text_prompt).get("text").get("text")
message_placeholder.markdown(full_response)
messages.append({"role": "assistant", "content": full_response})
# import streamlit as st
# import time
# def count_down(ts):
# with st.empty():
# while ts:
# mins, secs = divmod(ts, 60)
# time_now = '{:02d}:{:02d}'.format(mins, secs)
# st.header(f"{time_now}")
# time.sleep(1)
# ts -= 1
# st.write("Time Up!")
# def main():
# st.title("Pomodoro")
# time_minutes = st.number_input('Enter the time in minutes ', min_value=1, value=25)
# time_in_seconds = time_minutes * 60
# if st.button("START"):
# count_down(int(time_in_seconds))
# if __name__ == '__main__':
# main()