sunbal7 commited on
Commit
24ba781
Β·
verified Β·
1 Parent(s): f782c99

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +217 -238
app.py CHANGED
@@ -1,255 +1,234 @@
1
  import streamlit as st
2
- import random
3
- import time
4
- from streamlit.components.v1 import html
5
-
6
- # Set page config with light purple theme
 
 
 
 
 
 
 
7
  st.set_page_config(
8
- page_title="Emotion Mirror Chatbot",
9
- page_icon="😊",
10
- layout="centered",
11
  initial_sidebar_state="collapsed"
12
  )
13
 
14
- # Custom CSS for enhanced light purple theme
15
  st.markdown("""
16
  <style>
17
- :root {
18
- --primary: #b19cd9;
19
- --primary-dark: #8a7faa;
20
- --background: linear-gradient(135deg, #f5f0ff, #e6d7ff);
21
- --secondary-background: #e6e0fa;
22
- --text: #4a4a4a;
23
- --font: "Arial", sans-serif;
24
- }
25
-
26
- body {
27
- background-image: var(--background);
28
- background-attachment: fixed;
29
- color: var(--text);
30
- font-family: var(--font);
31
- }
32
-
33
- .stTextInput>div>div>input {
34
- background-color: var(--secondary-background) !important;
35
- color: var(--text) !important;
36
- border: 2px solid var(--primary) !important;
37
- border-radius: 12px;
38
- }
39
-
40
- .stButton>button {
41
- background-color: var(--primary) !important;
42
- color: white !important;
43
- border: none;
44
- border-radius: 12px;
45
- padding: 8px 16px;
46
- transition: all 0.3s ease;
47
- }
48
-
49
- .stButton>button:hover {
50
- background-color: var(--primary-dark) !important;
51
- transform: scale(1.05);
52
- }
53
-
54
- .stMarkdown {
55
- font-family: monospace !important;
56
- font-size: 16px !important;
57
- }
58
-
59
- .chat-message {
60
- padding: 12px 16px;
61
- border-radius: 16px;
62
- margin: 10px 0;
63
- max-width: 80%;
64
- box-shadow: 0 2px 6px rgba(0,0,0,0.1);
65
- }
66
-
67
- .user-message {
68
- background-color: var(--secondary-background);
69
- margin-left: auto;
70
- text-align: left;
71
- border-bottom-right-radius: 4px;
72
- }
73
-
74
- .bot-message {
75
- background-color: var(--primary);
76
- color: white;
77
- margin-right: auto;
78
- border-bottom-left-radius: 4px;
79
- }
80
-
81
- .face-container {
82
- text-align: center;
83
- padding: 20px;
84
- background: rgba(255, 255, 255, 0.7);
85
- backdrop-filter: blur(5px);
86
- border-radius: 20px;
87
- box-shadow: 0 8px 20px rgba(0,0,0,0.1);
88
- margin: 20px auto;
89
- max-width: 300px;
90
- border: 2px solid var(--primary);
91
- }
92
-
93
- .header {
94
- text-align: center;
95
- margin-bottom: 20px;
96
- }
97
-
98
- .title {
99
- color: var(--primary);
100
- font-size: 2.5rem;
101
- margin-bottom: 10px;
102
- text-shadow: 1px 1px 3px rgba(0,0,0,0.1);
103
- }
104
-
105
- .subtitle {
106
- color: var(--text);
107
- font-size: 1.1rem;
108
- margin-bottom: 30px;
109
- }
110
-
111
- .footer {
112
- text-align: center;
113
- margin-top: 30px;
114
- color: var(--primary);
115
- font-size: 0.9rem;
116
- }
117
  </style>
118
  """, unsafe_allow_html=True)
119
 
120
- # Emotion databases
121
- POSITIVE_WORDS = {"happy", "awesome", "great", "joy", "excited", "good", "wonderful", "fantastic", "amazing", "yay", "ecstatic"}
122
- NEGATIVE_WORDS = {"sad", "depressed", "angry", "cry", "lonely", "bad", "terrible", "awful", "miserable", "upset", "grief"}
123
- LOVE_WORDS = {"love", "heart", "adore", "crush", "romance", "affection", "passion"}
124
- HELP_RESPONSES = [
125
- "Would you like to talk about it? πŸ’¬",
126
- "I'm here to listen whenever you need πŸ’™",
127
- "Want some uplifting quotes? πŸ“œ",
128
- "Would a virtual hug help? πŸ€—",
129
- "Let's focus on something positive 🌈",
130
- "Remember: this too shall pass 🌀️"
131
- ]
132
-
133
- # ASCII Art Library
134
- FACES = {
135
- "happy": r"""
136
- ╔════════════╗
137
- πŸ˜„ AWESOME DAY!
138
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
139
- """,
140
- "sad": r"""
141
- ╔════════════╗
142
- 😒 TOUGH TIMES?
143
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
144
- """,
145
- "neutral": r"""
146
- ╔════════════╗
147
- 😐 HELLO THERE
148
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
149
- """,
150
- "love": r"""
151
- ╔════════════╗
152
- 😍 LOVELY FEELING!
153
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
154
- """,
155
- "angry": r"""
156
- ╔════════════╗
157
- 😠 TAKE A DEEP BREATH
158
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•
159
- """
160
- }
161
-
162
- # Confetti effect using JavaScript
163
- def confetti_effect():
164
- confetti_js = """
165
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
166
- <script>
167
- const count = 200;
168
- const defaults = {
169
- origin: { y: 0.7 }
170
- };
171
-
172
- function fire(particleRatio, opts) {
173
- confetti(Object.assign({}, defaults, opts, {
174
- particleCount: Math.floor(count * particleRatio),
175
- colors: ['#b19cd9', '#e6d7ff', '#8a7faa', '#ffffff']
176
- }));
177
- }
178
-
179
- fire(0.25, { spread: 26, startVelocity: 55 });
180
- fire(0.2, { spread: 60 });
181
- fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
182
- fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
183
- fire(0.1, { spread: 120, startVelocity: 45 });
184
- </script>
185
- """
186
- html(confetti_js)
187
-
188
- # Emotion detection function
189
- def detect_emotion(text):
190
- text = text.lower()
191
- if any(word in text for word in POSITIVE_WORDS):
192
- return "happy"
193
- elif any(word in text for word in NEGATIVE_WORDS):
194
- return "sad"
195
- elif any(word in text for word in LOVE_WORDS):
196
- return "love"
197
- elif "angry" in text or "mad" in text or "furious" in text:
198
- return "angry"
199
- return "neutral"
200
-
201
- # Initialize chat history
202
- if "messages" not in st.session_state:
203
- st.session_state.messages = []
204
- st.session_state.current_emotion = "neutral"
205
-
206
- # Header with title and description
207
- st.markdown('<div class="header"><div class="title">✨ Emotion Mirror Chatbot</div><div class="subtitle">I\'m a reactive AI agent that mirrors your emotions! Try words like <i>happy, sad, love,</i> or <i>awesome</i></div></div>', unsafe_allow_html=True)
208
-
209
- # Display current face
210
- with st.container():
211
- st.markdown(f"<div class='face-container'>\n{FACES[st.session_state.current_emotion]}\n</div>",
212
- unsafe_allow_html=True)
213
-
214
- # Display chat messages
215
- for message in st.session_state.messages:
216
- with st.chat_message(message["role"]):
217
- st.markdown(f"<div class='chat-message {message['role']}-message'>{message['content']}</div>",
218
- unsafe_allow_html=True)
219
-
220
- # User input
221
- if prompt := st.chat_input("How are you feeling today?"):
222
- # Add user message to chat history
223
- st.session_state.messages.append({"role": "user", "content": prompt})
224
 
225
- # Detect emotion
226
- emotion = detect_emotion(prompt)
227
- st.session_state.current_emotion = emotion
228
 
229
- # Generate bot response
230
- if emotion == "happy":
231
- response = FACES["happy"] + "\n\n🌟 That's wonderful to hear! Keep spreading positivity!"
232
- confetti_effect()
233
- elif emotion == "sad":
234
- response = FACES["sad"] + "\n\n" + random.choice(HELP_RESPONSES)
235
- elif emotion == "love":
236
- response = FACES["love"] + "\n\nπŸ’– Love is the most beautiful feeling! Treasure it."
237
- elif emotion == "angry":
238
- response = FACES["angry"] + "\n\n☁️ Take a deep breath. Count to ten. You've got this."
239
- else:
240
- response = FACES["neutral"] + "\n\nTell me more about your feelings..."
241
 
242
- # Add bot response to chat history
243
- st.session_state.messages.append({"role": "bot", "content": response})
244
 
245
- # Rerun to update the display
246
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
- # Add reset button
249
- if st.button("Reset Conversation"):
250
- st.session_state.messages = []
251
- st.session_state.current_emotion = "neutral"
252
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
  # Footer
255
- st.markdown('<div class="footer">Made with ❀️ | Reactive AI Agent | Streamlit</div>', unsafe_allow_html=True)
 
 
 
 
 
 
1
  import streamlit as st
2
+ from streamlit_option_menu import option_menu
3
+ import fitz # PyMuPDF
4
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
5
+ from langchain_community.embeddings import HuggingFaceEmbeddings
6
+ from langchain_community.vectorstores import FAISS
7
+ from langchain_community.llms import HuggingFaceHub
8
+ from langchain.chains import RetrievalQA
9
+ import tempfile
10
+ import os
11
+ import base64
12
+
13
+ # Page configuration
14
  st.set_page_config(
15
+ page_title="PDF Study Assistant",
16
+ page_icon="πŸ“š",
17
+ layout="wide",
18
  initial_sidebar_state="collapsed"
19
  )
20
 
21
+ # Custom CSS for colorful design
22
  st.markdown("""
23
  <style>
24
+ :root {
25
+ --primary: #ff4b4b;
26
+ --secondary: #ff9a3d;
27
+ --accent1: #ffcb74;
28
+ --accent2: #3a86ff;
29
+ --background: #f0f2f6;
30
+ --card: #ffffff;
31
+ }
32
+
33
+ .stApp {
34
+ background: linear-gradient(135deg, var(--background) 0%, #e0e5ec 100%);
35
+ }
36
+
37
+ .stButton>button {
38
+ background: linear-gradient(to right, var(--secondary), var(--primary));
39
+ color: white;
40
+ border-radius: 12px;
41
+ padding: 8px 20px;
42
+ font-weight: 600;
43
+ }
44
+
45
+ .stTextInput>div>div>input {
46
+ border-radius: 12px;
47
+ border: 2px solid var(--accent2);
48
+ padding: 10px;
49
+ }
50
+
51
+ .card {
52
+ background: var(--card);
53
+ border-radius: 15px;
54
+ box-shadow: 0 8px 16px rgba(0,0,0,0.1);
55
+ padding: 20px;
56
+ margin-bottom: 20px;
57
+ }
58
+
59
+ .header {
60
+ background: linear-gradient(to right, var(--accent2), var(--primary));
61
+ -webkit-background-clip: text;
62
+ -webkit-text-fill-color: transparent;
63
+ text-align: center;
64
+ margin-bottom: 30px;
65
+ }
66
+
67
+ .tab-content {
68
+ animation: fadeIn 0.5s ease-in-out;
69
+ }
70
+
71
+ @keyframes fadeIn {
72
+ from { opacity: 0; }
73
+ to { opacity: 1; }
74
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  </style>
76
  """, unsafe_allow_html=True)
77
 
78
+ # Initialize session state
79
+ if 'pdf_processed' not in st.session_state:
80
+ st.session_state.pdf_processed = False
81
+ if 'qa_chain' not in st.session_state:
82
+ st.session_state.qa_chain = None
83
+ if 'pages' not in st.session_state:
84
+ st.session_state.pages = []
85
+
86
+ # Load models with caching
87
+ @st.cache_resource
88
+ def load_embedding_model():
89
+ return HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
90
+
91
+ @st.cache_resource
92
+ def load_qa_model():
93
+ return HuggingFaceHub(
94
+ repo_id="google/flan-t5-xxl",
95
+ model_kwargs={"temperature": 0.5, "max_length": 512},
96
+ huggingfacehub_api_token=os.getenv("HF_API_KEY")
97
+ )
98
+
99
+ def process_pdf(pdf_file):
100
+ """Extract text from PDF and create vector store"""
101
+ with st.spinner("πŸ“– Reading PDF..."):
102
+ doc = fitz.open(stream=pdf_file.read(), filetype="pdf")
103
+ text = ""
104
+ st.session_state.pages = []
105
+ for page in doc:
106
+ text += page.get_text()
107
+ st.session_state.pages.append(page.get_text())
108
+
109
+ with st.spinner("πŸ” Processing text..."):
110
+ text_splitter = RecursiveCharacterTextSplitter(
111
+ chunk_size=1000,
112
+ chunk_overlap=200,
113
+ length_function=len
114
+ )
115
+ chunks = text_splitter.split_text(text)
116
+
117
+ embeddings = load_embedding_model()
118
+ vector_store = FAISS.from_texts(chunks, embeddings)
119
+
120
+ qa_model = load_qa_model()
121
+ st.session_state.qa_chain = RetrievalQA.from_chain_type(
122
+ llm=qa_model,
123
+ chain_type="stuff",
124
+ retriever=vector_store.as_retriever(search_kwargs={"k": 3}),
125
+ return_source_documents=True
126
+ )
127
+
128
+ st.session_state.pdf_processed = True
129
+ st.success("βœ… PDF processed successfully!")
130
+
131
+ def generate_qa_for_chapter(start_page, end_page):
132
+ """Generate Q&A for specific chapter pages"""
133
+ if start_page < 1 or end_page > len(st.session_state.pages) or start_page > end_page:
134
+ st.error("Invalid page range")
135
+ return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
+ chapter_text = "\n".join(st.session_state.pages[start_page-1:end_page])
 
 
138
 
139
+ text_splitter = RecursiveCharacterTextSplitter(
140
+ chunk_size=800,
141
+ chunk_overlap=100,
142
+ length_function=len
143
+ )
144
+ chunks = text_splitter.split_text(chapter_text)
 
 
 
 
 
 
145
 
146
+ qa_pairs = []
147
+ qa_model = load_qa_model()
148
 
149
+ with st.spinner(f"🧠 Generating Q&A for pages {start_page}-{end_page}..."):
150
+ for i, chunk in enumerate(chunks):
151
+ if i % 2 == 0: # Generate question
152
+ prompt = f"Generate a study question based on: {chunk[:500]}"
153
+ question = qa_model(prompt)[:120] + "?"
154
+ else: # Generate answer
155
+ prompt = f"Answer the question: {qa_pairs[-1][0]} using context: {chunk[:500]}"
156
+ answer = qa_model(prompt)
157
+ qa_pairs[-1] = (qa_pairs[-1][0], answer)
158
+
159
+ return qa_pairs
160
+
161
+ # App header
162
+ st.markdown("<h1 class='header'>πŸ“š PDF Study Assistant</h1>", unsafe_allow_html=True)
163
+
164
+ # PDF Upload Section
165
+ with st.container():
166
+ st.subheader("πŸ“€ Upload Your Textbook/Notes")
167
+ pdf_file = st.file_uploader("", type="pdf", label_visibility="collapsed")
168
 
169
+ # Main content
170
+ if pdf_file:
171
+ if not st.session_state.pdf_processed:
172
+ process_pdf(pdf_file)
173
+
174
+ if st.session_state.pdf_processed:
175
+ # Navigation tabs
176
+ selected_tab = option_menu(
177
+ None,
178
+ ["Ask Questions", "Generate Chapter Q&A"],
179
+ icons=["chat", "book"],
180
+ menu_icon="cast",
181
+ default_index=0,
182
+ orientation="horizontal",
183
+ styles={
184
+ "container": {"padding": "0!important", "background-color": "#f9f9f9"},
185
+ "nav-link": {"font-size": "16px", "font-weight": "bold"},
186
+ "nav-link-selected": {"background": "linear-gradient(to right, #3a86ff, #ff4b4b)"},
187
+ }
188
+ )
189
+
190
+ # Question Answering Tab
191
+ if selected_tab == "Ask Questions":
192
+ st.markdown("### πŸ’¬ Ask Questions About Your Document")
193
+ user_question = st.text_input("Type your question here:", key="user_question")
194
+
195
+ if user_question:
196
+ with st.spinner("πŸ€” Thinking..."):
197
+ result = st.session_state.qa_chain({"query": user_question})
198
+ st.markdown(f"<div class='card'><b>Answer:</b> {result['result']}</div>", unsafe_allow_html=True)
199
+
200
+ with st.expander("πŸ” See source passages"):
201
+ for i, doc in enumerate(result["source_documents"]):
202
+ st.markdown(f"**Passage {i+1}:** {doc.page_content[:500]}...")
203
+
204
+ # Chapter Q&A Generation Tab
205
+ elif selected_tab == "Generate Chapter Q&A":
206
+ st.markdown("### πŸ“ Generate Q&A for Specific Chapter")
207
+ col1, col2 = st.columns(2)
208
+ with col1:
209
+ start_page = st.number_input("Start Page", min_value=1, max_value=len(st.session_state.pages), value=1)
210
+ with col2:
211
+ end_page = st.number_input("End Page", min_value=1, max_value=len(st.session_state.pages), value=min(5, len(st.session_state.pages)))
212
+
213
+ if st.button("Generate Q&A", key="generate_qa"):
214
+ qa_pairs = generate_qa_for_chapter(start_page, end_page)
215
+
216
+ if qa_pairs:
217
+ st.markdown(f"<h4>πŸ“– Generated Questions for Pages {start_page}-{end_page}</h4>", unsafe_allow_html=True)
218
+ for i, (question, answer) in enumerate(qa_pairs):
219
+ st.markdown(f"""
220
+ <div class='card'>
221
+ <b>Q{i+1}:</b> {question}<br>
222
+ <b>A{i+1}:</b> {answer}
223
+ </div>
224
+ """, unsafe_allow_html=True)
225
+ else:
226
+ st.warning("No Q&A pairs generated. Try a different page range.")
227
 
228
  # Footer
229
+ st.markdown("---")
230
+ st.markdown("""
231
+ <div style="text-align: center; padding: 20px;">
232
+ Built with ❀️ for students | PDF Study Assistant v1.0
233
+ </div>
234
+ """, unsafe_allow_html=True)