|
|
import streamlit as st |
|
|
import os |
|
|
import requests |
|
|
from bs4 import BeautifulSoup |
|
|
from langchain.embeddings import OpenAIEmbeddings |
|
|
from langchain.vectorstores import FAISS |
|
|
from langchain.text_splitter import RecursiveCharacterTextSplitter |
|
|
from langchain.memory import ConversationBufferMemory |
|
|
from langchain.chat_models import ChatOpenAI |
|
|
from langchain.agents import initialize_agent, AgentType |
|
|
from langchain.tools import Tool |
|
|
from langchain.chains import RetrievalQA |
|
|
|
|
|
|
|
|
st.set_page_config(page_title="Book Q&A System", page_icon="π") |
|
|
|
|
|
|
|
|
st.title("Alice in Wonderland Q&A System") |
|
|
|
|
|
|
|
|
with st.sidebar: |
|
|
st.title("Settings") |
|
|
|
|
|
|
|
|
st.markdown("### OpenAI API Key") |
|
|
st.markdown("**Enter your OpenAI API key to use this application**") |
|
|
openai_api_key = st.text_input("OpenAI API Key", type="password", |
|
|
help="Get your API key from https://platform.openai.com/account/api-keys") |
|
|
|
|
|
|
|
|
if st.button("Validate API Key"): |
|
|
if not openai_api_key: |
|
|
st.error("Please enter an API key") |
|
|
else: |
|
|
try: |
|
|
|
|
|
os.environ["OPENAI_API_KEY"] = openai_api_key |
|
|
|
|
|
|
|
|
llm = ChatOpenAI( |
|
|
model_name="gpt-3.5-turbo", |
|
|
temperature=0 |
|
|
) |
|
|
|
|
|
|
|
|
result = llm.predict("Say 'API key is valid' if you can read this.") |
|
|
|
|
|
if "API key is valid" in result: |
|
|
st.success("API key is valid!") |
|
|
else: |
|
|
st.error("API key validation failed.") |
|
|
except Exception as e: |
|
|
st.error(f"API key error: {str(e)}") |
|
|
|
|
|
|
|
|
if st.button("Reset Chat"): |
|
|
st.session_state.messages = [] |
|
|
st.session_state.agent = None |
|
|
st.session_state.book_processed = False |
|
|
st.experimental_rerun() |
|
|
|
|
|
|
|
|
if "messages" not in st.session_state: |
|
|
st.session_state.messages = [] |
|
|
if "book_processed" not in st.session_state: |
|
|
st.session_state.book_processed = False |
|
|
|
|
|
|
|
|
for message in st.session_state.messages: |
|
|
with st.chat_message(message["role"]): |
|
|
st.markdown(message["content"]) |
|
|
|
|
|
|
|
|
book_url = "https://www.gutenberg.org/files/11/11-0.txt" |
|
|
|
|
|
|
|
|
@st.cache_resource |
|
|
def process_book(book_url, api_key): |
|
|
|
|
|
response = requests.get(book_url) |
|
|
if response.status_code != 200: |
|
|
return "Error downloading the book" |
|
|
|
|
|
|
|
|
text = response.text |
|
|
|
|
|
|
|
|
soup = BeautifulSoup(text, 'html.parser') |
|
|
cleaned_text = soup.get_text() |
|
|
|
|
|
|
|
|
text_splitter = RecursiveCharacterTextSplitter( |
|
|
chunk_size=1000, |
|
|
chunk_overlap=200, |
|
|
length_function=len |
|
|
) |
|
|
chunks = text_splitter.split_text(cleaned_text) |
|
|
|
|
|
|
|
|
embeddings = OpenAIEmbeddings( |
|
|
openai_api_key=openai_api_key |
|
|
) |
|
|
|
|
|
|
|
|
vector_store = FAISS.from_texts(chunks, embeddings) |
|
|
|
|
|
return vector_store |
|
|
|
|
|
|
|
|
def create_langchain_agent(vector_store): |
|
|
|
|
|
os.environ["OPENAI_API_KEY"] = openai_api_key |
|
|
|
|
|
llm = ChatOpenAI( |
|
|
model_name="gpt-3.5-turbo", |
|
|
temperature=0.7 |
|
|
) |
|
|
|
|
|
|
|
|
retrieval_qa = RetrievalQA.from_chain_type( |
|
|
llm=llm, |
|
|
chain_type="stuff", |
|
|
retriever=vector_store.as_retriever(search_kwargs={"k": 3}) |
|
|
) |
|
|
|
|
|
tools = [ |
|
|
Tool( |
|
|
name="BookQATool", |
|
|
func=retrieval_qa.run, |
|
|
description="Useful for answering questions about Alice in Wonderland. Input should be a question about the book." |
|
|
) |
|
|
] |
|
|
|
|
|
|
|
|
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) |
|
|
|
|
|
|
|
|
agent = initialize_agent( |
|
|
tools, |
|
|
llm, |
|
|
agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION, |
|
|
verbose=True, |
|
|
memory=memory, |
|
|
handle_parsing_errors=True |
|
|
) |
|
|
|
|
|
return agent |
|
|
|
|
|
|
|
|
if not openai_api_key: |
|
|
|
|
|
st.warning(" Please enter your OpenAI API key in the sidebar to use this application.") |
|
|
|
|
|
else: |
|
|
|
|
|
if not st.session_state.book_processed: |
|
|
with st.spinner("Processing Alice in Wonderland... This may take a minute."): |
|
|
vector_store = process_book(book_url, openai_api_key) |
|
|
st.session_state.agent = create_langchain_agent(vector_store) |
|
|
st.session_state.book_processed = True |
|
|
st.success("Alice in Wonderland processed successfully!") |
|
|
|
|
|
|
|
|
if prompt := st.chat_input("Ask a question about Alice in Wonderland"): |
|
|
|
|
|
st.session_state.messages.append({"role": "user", "content": prompt}) |
|
|
|
|
|
|
|
|
with st.chat_message("user"): |
|
|
st.markdown(prompt) |
|
|
|
|
|
|
|
|
with st.chat_message("assistant"): |
|
|
with st.spinner("Thinking..."): |
|
|
try: |
|
|
response = st.session_state.agent.run(input=prompt) |
|
|
st.markdown(response) |
|
|
except Exception as e: |
|
|
st.error(f"Error: {str(e)}") |
|
|
response = "I encountered an error processing your question. Please try a different question or reset the chat." |
|
|
st.markdown(response) |
|
|
|
|
|
|
|
|
st.session_state.messages.append({"role": "assistant", "content": response}) |