simple-llm-app / app.py
jtaicp's picture
Initial commit
09ac1df verified
Raw
History Blame Contribute Delete
4.96 kB
import os
from operator import itemgetter
import chainlit as cl
from langchain import hub
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.messages import AIMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import ConfigurableFieldSpec, RunnablePassthrough
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from lib.in_memory_history import InMemoryHistory
from lib.indexing import (create_search_engine, format_docs,
load_and_split_documents)
from lib.prompts import EXAMPLE_PROMPT, PROMPT, WELCOME_MESSAGE
llm_model = "gpt-3.5-turbo"
temperature=0.0
store = {}
# Fetch message history
def get_session_history(user_id: str, conversation_id: str) -> BaseChatMessageHistory:
if (user_id, conversation_id) not in store:
store[(user_id, conversation_id)] = InMemoryHistory()
return store[(user_id, conversation_id)]
history = get_session_history("1", "1")
history.add_message(AIMessage(content="hello"))
print(store)
@cl.on_chat_start
async def init():
"""This function is run at every chat session starts to ask user for file,
index it, and build the RAG chain.
Raises:
SystemError: yolo
"""
await cl.Avatar(
name="Chatbot",
url="https://www.aicatalystpartners.com/hubfs/favicon/ms-icon-310x310.png",
).send()
files = None
# Asking user to to upload a PDF to chat with
while files == None:
files = await cl.AskFileMessage(
content=WELCOME_MESSAGE,
accept=["application/pdf"],
max_size_mb=24,
timeout=180,
).send()
file = files[0]
msg = cl.Message(content=f"Processing `{file.name}`...", disable_feedback=True)
await msg.send()
docs = load_and_split_documents(file=file)
cl.user_session.set("docs", docs)
msg.content = f"The file '{file.name}' has been processed. Loading index ..."
await msg.update()
# Index documents into search engine
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002") # we can define a different embedding model in future
try:
search_engine = await cl.make_async(create_search_engine)(
docs=docs, embeddings=embeddings
)
except Exception as e:
await cl.Message(content=f"Error: {e}").send()
raise SystemError
# Prompt - using an external prompt template
prompt = hub.pull("rlm/rag-prompt")
# LLM model
llm = ChatOpenAI(temperature=temperature, model=llm_model, streaming=True)
# Output parser
output_parser = StrOutputParser()
# RAG Chain
context = itemgetter("question") | search_engine.as_retriever(search_kwargs={'k': 4}, max_tokens_limit=4097) | format_docs
first_step = RunnablePassthrough.assign(context=context)
rag_chain = first_step | prompt | llm
rag_chain_with_mgs_history = RunnableWithMessageHistory(
rag_chain, # type: ignore
get_session_history=get_session_history,
input_messages_key="question",
history_messages_key="history",
history_factory_config=[
ConfigurableFieldSpec(
id="user_id",
annotation=str,
name="User ID",
description="Unique identifier for the user.",
default="",
is_shared=True,
),
ConfigurableFieldSpec(
id="conversation_id",
annotation=str,
name="Conversation ID",
description="Unique identifier for the conversation.",
default="",
is_shared=True,
),
],
) | output_parser
# Let the user know that the RAG QA system is ready
msg.content = f"The file '{file.name}' has been processed and the index has been loaded. You can now ask questions!"
await msg.update()
cl.user_session.set("runnable", rag_chain_with_mgs_history)
@cl.on_message
async def on_message(message: cl.Message):
"""This function is invoked whenever we receive a Chainlit message.
Args:
message (cl.Message): user input
"""
runnable_chain = cl.user_session.get("runnable") # type: ignore # type:
cb = cl.AsyncLangchainCallbackHandler(stream_final_answer=True)
response = await runnable_chain.ainvoke( # type: ignore # type: RunnableWithMessageHistory
{"question": message.content},
config = {
"configurable": {"user_id": "user_id", "conversation_id": "conversation_id"},
"callbacks": [cb]
},
)
await cl.Message(content=response).send()
msg = cl.Message(content="")