nivakaran commited on
Commit
f41da3d
·
verified ·
1 Parent(s): aa4a033

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +59 -19
src/streamlit_app.py CHANGED
@@ -2,6 +2,7 @@ import os
2
  import re
3
  import logging
4
  from uuid import uuid4
 
5
  from dotenv import load_dotenv
6
  import streamlit as st
7
 
@@ -19,6 +20,25 @@ from langchain_chroma import Chroma
19
  logging.basicConfig(level=logging.INFO)
20
  logger = logging.getLogger(__name__)
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  # Load environment variables
23
  load_dotenv()
24
  HF_TOKEN = os.getenv("HF_TOKEN")
@@ -30,12 +50,20 @@ if not all([HF_TOKEN, GROQ_API_KEY, PDF_PATH]):
30
  st.error("Missing required environment variables")
31
  st.stop()
32
 
33
- # Initialize RAG components
34
- embeddings = HuggingFaceEmbeddings(
35
- model_name="sentence-transformers/all-MiniLM-L6-v2",
36
- cache_folder="./cache/huggingface"
37
- )
38
- llm = ChatGroq(model_name="Deepseek-R1-Distill-Llama-70b")
 
 
 
 
 
 
 
 
39
  session_store = {}
40
 
41
  # Process PDF into vectorstore
@@ -45,10 +73,13 @@ def process_pdf(file_path: str):
45
  documents = loader.load()
46
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=5000, chunk_overlap=500)
47
  splits = text_splitter.split_documents(documents)
 
 
 
48
  vectorstore = Chroma.from_documents(
49
  documents=splits,
50
  embedding=embeddings,
51
- persist_directory="./portfolio.db"
52
  )
53
  logger.info(f"PDF {file_path} processed successfully")
54
  return vectorstore
@@ -58,30 +89,35 @@ def process_pdf(file_path: str):
58
  st.stop()
59
 
60
  # Initialize vectorstore and retriever
61
- vectorstore = process_pdf(PDF_PATH)
62
- retriever = vectorstore.as_retriever()
 
 
 
 
 
63
 
64
  # System prompt for the assistant
65
  system_prompt = """You are Max, a friendly and professional chatbot designed to
66
- assist visitors to Nivakarans portfolio website. Your primary goal
67
  is to provide accurate, clear, and helpful information about Nivakaran, based
68
  on the following context:
69
 
70
  {context}
71
 
72
  Your responses should be:
73
- 1. Informative and relevant, directly addressing the visitors questions about Nivakarans skills,
74
  projects, experience, and background.
75
- 2. Concise but thorough enough to give visitors a clear understanding of Nivakarans expertise.
76
  3. Engaging and approachable, maintaining a professional yet conversational tone.
77
- 4. Honest about what is available in the provided context; if you dont know an answer, politely
78
  say so and suggest the visitor explore other sections of the portfolio or contact Nivakaran directly.
79
- 5. Focused on helping visitors understand Nivakarans capabilities and what makes him stand out
80
  as a developer and professional.
81
  6. Ready to provide examples, explanations, or links to portfolio projects when relevant.
82
 
83
  Avoid providing generic or unrelated information. Always tailor your answers to
84
- highlight Nivakarans strengths and the unique value he brings.
85
  """
86
 
87
  # Streamlit app UI
@@ -111,10 +147,11 @@ if user_input := st.chat_input("Ask me something about Nivakaran..."):
111
 
112
  # Contextualize question based on history
113
  contextualize_q_prompt = ChatPromptTemplate.from_messages([
114
- ("system", "Rephrase questions considering chat history."),
115
  MessagesPlaceholder("chat_history"),
116
  ("human", "{input}")
117
  ])
 
118
  history_aware_retriever = create_history_aware_retriever(
119
  llm, retriever, contextualize_q_prompt
120
  )
@@ -125,6 +162,7 @@ if user_input := st.chat_input("Ask me something about Nivakaran..."):
125
  MessagesPlaceholder("chat_history"),
126
  ("human", "{input}")
127
  ])
 
128
  question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
129
  rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
130
 
@@ -132,10 +170,11 @@ if user_input := st.chat_input("Ask me something about Nivakaran..."):
132
  "input": user_input,
133
  "chat_history": last_messages
134
  })
 
135
  raw_answer = result["answer"]
136
-
137
- # Clean out <think>...</think> junk
138
  cleaned_answer = re.sub(r"<think>.*?</think>\s*", "", raw_answer, flags=re.DOTALL).strip()
 
139
 
140
  with st.chat_message("assistant"):
141
  st.markdown(cleaned_answer)
@@ -143,4 +182,5 @@ if user_input := st.chat_input("Ask me something about Nivakaran..."):
143
  st.session_state.history.add_ai_message(cleaned_answer)
144
 
145
  except Exception as e:
146
- st.error(f"Error: {str(e)}")
 
 
2
  import re
3
  import logging
4
  from uuid import uuid4
5
+ from pathlib import Path
6
  from dotenv import load_dotenv
7
  import streamlit as st
8
 
 
20
  logging.basicConfig(level=logging.INFO)
21
  logger = logging.getLogger(__name__)
22
 
23
+ # Set up proper cache directories for HuggingFace Spaces
24
+ def setup_environment():
25
+ # Create cache directories in a writable location
26
+ cache_dir = Path("/tmp/cache") # Using /tmp which is writable in HuggingFace Spaces
27
+ cache_dir.mkdir(exist_ok=True)
28
+
29
+ # Set environment variables
30
+ os.environ['STREAMLIT_HOME'] = str(cache_dir / "streamlit")
31
+ os.environ['HF_HOME'] = str(cache_dir / "huggingface")
32
+ os.environ['TRANSFORMERS_CACHE'] = str(cache_dir / "transformers")
33
+ os.environ['XDG_CACHE_HOME'] = str(cache_dir)
34
+
35
+ # Ensure subdirectories exist
36
+ (cache_dir / "huggingface").mkdir(exist_ok=True)
37
+ (cache_dir / "streamlit").mkdir(exist_ok=True)
38
+ (cache_dir / "transformers").mkdir(exist_ok=True)
39
+
40
+ setup_environment()
41
+
42
  # Load environment variables
43
  load_dotenv()
44
  HF_TOKEN = os.getenv("HF_TOKEN")
 
50
  st.error("Missing required environment variables")
51
  st.stop()
52
 
53
+ # Initialize RAG components with proper cache handling
54
+ try:
55
+ embeddings = HuggingFaceEmbeddings(
56
+ model_name="sentence-transformers/all-MiniLM-L6-v2",
57
+ model_kwargs={'device': 'cpu'},
58
+ encode_kwargs={'normalize_embeddings': True},
59
+ cache_folder=os.environ['HF_HOME']
60
+ )
61
+ except Exception as e:
62
+ logger.error(f"Failed to initialize embeddings: {str(e)}")
63
+ st.error("Failed to initialize embeddings. Please try again later.")
64
+ st.stop()
65
+
66
+ llm = ChatGroq(model_name="Deepseek-R1-Distill-Llama-70b", temperature=0.1)
67
  session_store = {}
68
 
69
  # Process PDF into vectorstore
 
73
  documents = loader.load()
74
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=5000, chunk_overlap=500)
75
  splits = text_splitter.split_documents(documents)
76
+
77
+ # Use temporary directory for Chroma DB
78
+ chroma_dir = "/tmp/chroma_db"
79
  vectorstore = Chroma.from_documents(
80
  documents=splits,
81
  embedding=embeddings,
82
+ persist_directory=chroma_dir
83
  )
84
  logger.info(f"PDF {file_path} processed successfully")
85
  return vectorstore
 
89
  st.stop()
90
 
91
  # Initialize vectorstore and retriever
92
+ try:
93
+ vectorstore = process_pdf(PDF_PATH)
94
+ retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
95
+ except Exception as e:
96
+ logger.error(f"Failed to initialize vectorstore: {str(e)}")
97
+ st.error("Failed to initialize document store. Please try again later.")
98
+ st.stop()
99
 
100
  # System prompt for the assistant
101
  system_prompt = """You are Max, a friendly and professional chatbot designed to
102
+ assist visitors to Nivakaran's portfolio website. Your primary goal
103
  is to provide accurate, clear, and helpful information about Nivakaran, based
104
  on the following context:
105
 
106
  {context}
107
 
108
  Your responses should be:
109
+ 1. Informative and relevant, directly addressing the visitor's questions about Nivakaran's skills,
110
  projects, experience, and background.
111
+ 2. Concise but thorough enough to give visitors a clear understanding of Nivakaran's expertise.
112
  3. Engaging and approachable, maintaining a professional yet conversational tone.
113
+ 4. Honest about what is available in the provided context; if you don't know an answer, politely
114
  say so and suggest the visitor explore other sections of the portfolio or contact Nivakaran directly.
115
+ 5. Focused on helping visitors understand Nivakaran's capabilities and what makes him stand out
116
  as a developer and professional.
117
  6. Ready to provide examples, explanations, or links to portfolio projects when relevant.
118
 
119
  Avoid providing generic or unrelated information. Always tailor your answers to
120
+ highlight Nivakaran's strengths and the unique value he brings.
121
  """
122
 
123
  # Streamlit app UI
 
147
 
148
  # Contextualize question based on history
149
  contextualize_q_prompt = ChatPromptTemplate.from_messages([
150
+ ("system", "Given a chat history and the latest user question which might reference context in the chat history, formulate a standalone question which can be understood without the chat history. Return just the question and nothing else."),
151
  MessagesPlaceholder("chat_history"),
152
  ("human", "{input}")
153
  ])
154
+
155
  history_aware_retriever = create_history_aware_retriever(
156
  llm, retriever, contextualize_q_prompt
157
  )
 
162
  MessagesPlaceholder("chat_history"),
163
  ("human", "{input}")
164
  ])
165
+
166
  question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
167
  rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
168
 
 
170
  "input": user_input,
171
  "chat_history": last_messages
172
  })
173
+
174
  raw_answer = result["answer"]
175
+ # Clean out <think>...</think> junk and any other unwanted artifacts
 
176
  cleaned_answer = re.sub(r"<think>.*?</think>\s*", "", raw_answer, flags=re.DOTALL).strip()
177
+ cleaned_answer = re.sub(r"<\|.*?\|>", "", cleaned_answer).strip()
178
 
179
  with st.chat_message("assistant"):
180
  st.markdown(cleaned_answer)
 
182
  st.session_state.history.add_ai_message(cleaned_answer)
183
 
184
  except Exception as e:
185
+ logger.error(f"Error during RAG processing: {str(e)}")
186
+ st.error("Sorry, I encountered an error while processing your request. Please try again.")