JustusI commited on
Commit
e75b4e2
·
verified ·
1 Parent(s): 24b7fa7

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +1142 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,1144 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import tempfile
3
+ import json
4
+ import random
5
+ from pathlib import Path
6
+ from PyPDF2 import PdfReader
7
+ from openai import OpenAI
8
+ import os
9
+ from ast import literal_eval
10
 
11
+ # Initialize the OpenAI client
12
+ api_key = os.getenv("OPENAI_API_KEY")
13
+ client = OpenAI(api_key = api_key)
14
+
15
+
16
+
17
+ # ---------------------------
18
+ # Helper Function: Extract text from PDF
19
+ # ---------------------------
20
+ def extract_text(uploaded_file):
21
+ # Check file size (max 10MB)
22
+ uploaded_file.seek(0, os.SEEK_END)
23
+ file_size = uploaded_file.tell()
24
+ uploaded_file.seek(0)
25
+ if file_size > 10 * 1024 * 1024:
26
+ st.error("File size exceeds 10MB limit.")
27
+ return ""
28
+ pdf_reader = PdfReader(uploaded_file)
29
+ text = ""
30
+ for page in pdf_reader.pages:
31
+ page_text = page.extract_text()
32
+ if page_text:
33
+ text += page_text + "\n"
34
+ return text
35
+
36
+ # ---------------------------
37
+ # OpenAI Response Functions (using new style)
38
+ # ---------------------------
39
+ def generate_summary_from_text(text):
40
+ prompt = (
41
+ f"Summarize the following document in a concise manner, highlighting the key points that a student should know:\n\n{text}"
42
+ )
43
+ messages = [
44
+ {"role": "system", "content": "You are an educational assistant."},
45
+ {"role": "user", "content": prompt}
46
+ ]
47
+ completion = client.chat.completions.create(
48
+ model="gpt-4o-mini",
49
+ messages=messages
50
+ )
51
+ return completion.choices[0].message.content.strip()
52
+
53
+ def chat_with_document(text, conversation_history, user_query):
54
+ messages = conversation_history + [
55
+ {"role": "user", "content": f"Based on the following document:\n\n{text}\n\nQuestion: {user_query}"}
56
+ ]
57
+ completion = client.chat.completions.create(
58
+ model="gpt-4o-mini",
59
+ messages=messages
60
+ )
61
+ return completion.choices[0].message.content.strip()
62
+
63
+ def generate_questions_from_text(text, num_questions):
64
+ prompt = (
65
+ f"Generate up to {num_questions} study questions with answers based on the following document.\n"
66
+ f"Return the output as a table with two columns: 'Question' and 'Answer'.\n\nDocument:\n\n{text}"
67
+ )
68
+ messages = [
69
+ {"role": "system", "content": "You are an educational assistant that generates study questions."},
70
+ {"role": "user", "content": prompt}
71
+ ]
72
+ completion = client.chat.completions.create(
73
+ model="gpt-4o-mini",
74
+ messages=messages
75
+ )
76
+ return completion.choices[0].message.content.strip()
77
+
78
+ def generate_flashcards_from_text(text, num_cards):
79
+ prompt = (
80
+ f"Generate {num_cards} flashcards based on the following document.\n\nDocument:\n\n{text}\n\n"
81
+ "Return a Python dictionary where each key is a flashcard question and its corresponding value is the answer. "
82
+ "Do not include any additional text."
83
+ )
84
+ messages = [
85
+ {"role": "system", "content": "You are an educational assistant that creates study flashcards."},
86
+ {"role": "user", "content": prompt}
87
+ ]
88
+ completion = client.chat.completions.create(
89
+ model="gpt-4o-mini",
90
+ messages=messages
91
+ )
92
+ output = completion.choices[0].message.content.strip()
93
+ try:
94
+ flashcards = literal_eval(output)
95
+ if isinstance(flashcards, dict):
96
+ return flashcards
97
+ else:
98
+ return {}
99
+ except Exception as e:
100
+ st.error(f"Error parsing flashcards: {e}")
101
+ return {}
102
+
103
+ # ---------------------------
104
+ # Sidebar: File Upload & Mode Selection
105
+ # ---------------------------
106
+ st.sidebar.markdown("""
107
+ <style>
108
+ .sidebar-title {
109
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
110
+ padding: 20px;
111
+ border-radius: 10px;
112
+ color: white;
113
+ text-align: center;
114
+ margin-bottom: 20px;
115
+ font-size: 1.3em;
116
+ font-weight: bold;
117
+ }
118
+ </style>
119
+ <div class="sidebar-title">
120
+ ⚙️ Study Companion Setup
121
+ </div>
122
+ """, unsafe_allow_html=True)
123
+
124
+ uploaded_pdf = st.sidebar.file_uploader("📄 Upload your study PDF (max 10MB)", type="pdf")
125
+ st.sidebar.markdown("---")
126
+ mode = st.sidebar.radio("🎯 Select Mode", ("Chat", "Test Your Knowledge", "Flashcards"))
127
+
128
+ # For Test Your Knowledge and Flashcards modes, allow number input.
129
+ num_questions = None
130
+ num_flashcards = None
131
+ if mode == "Test Your Knowledge":
132
+ num_questions = st.sidebar.number_input("Number of questions to generate (max 50):", min_value=1, max_value=50, value=10, step=1)
133
+ elif mode == "Flashcards":
134
+ num_flashcards = st.sidebar.number_input("Number of flashcards to generate (max 20):", min_value=1, max_value=20, value=5, step=1)
135
+
136
+ # ---------------------------
137
+ # Session State Initialization
138
+ # ---------------------------
139
+ if "pdf_text" not in st.session_state:
140
+ st.session_state.pdf_text = None
141
+ if "summary" not in st.session_state:
142
+ st.session_state.summary = None
143
+ if "chat_history" not in st.session_state:
144
+ st.session_state.chat_history = [{"role": "assistant", "content": "Hi, how can I help you with your study material?"}]
145
+ if "questions_table" not in st.session_state:
146
+ st.session_state.questions_table = None
147
+ if "flashcards" not in st.session_state:
148
+ st.session_state.flashcards = {}
149
+ if "current_card" not in st.session_state:
150
+ st.session_state.current_card = 0
151
+ if "score" not in st.session_state:
152
+ st.session_state.score = 0
153
+ if "show_answer" not in st.session_state:
154
+ st.session_state.show_answer = False
155
+ if "flashcard_keys" not in st.session_state:
156
+ st.session_state.flashcard_keys = []
157
+ if "user_answers" not in st.session_state:
158
+ st.session_state.user_answers = {}
159
+ if "shuffle_cards" not in st.session_state:
160
+ st.session_state.shuffle_cards = False
161
+
162
+ # ---------------------------
163
+ # Process PDF Upload
164
+ # ---------------------------
165
+ if uploaded_pdf is not None:
166
+ st.session_state.pdf_text = extract_text(uploaded_pdf)
167
+ if st.session_state.pdf_text:
168
+ st.sidebar.success("PDF uploaded and processed successfully!")
169
+ else:
170
+ st.sidebar.error("Failed to extract text. Please check your PDF file.")
171
+
172
+ # ---------------------------
173
+ # Main Area: Mode-Based Display (all functions via side menu)
174
+ # ---------------------------
175
+ # Page configuration and custom styling
176
+ st.markdown("""
177
+ <style>
178
+ /* Global styling */
179
+ .main {
180
+ background-color: #f5f7fa;
181
+ }
182
+
183
+ /* Header styling */
184
+ .main-header {
185
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
186
+ padding: 30px;
187
+ border-radius: 15px;
188
+ text-align: center;
189
+ color: white;
190
+ margin-bottom: 30px;
191
+ box-shadow: 0 5px 20px rgba(0,0,0,0.2);
192
+ }
193
+
194
+ .main-header h1 {
195
+ margin: 0;
196
+ font-size: 2.5em;
197
+ }
198
+
199
+ .main-header p {
200
+ margin: 10px 0 0 0;
201
+ font-size: 1.1em;
202
+ opacity: 0.9;
203
+ }
204
+
205
+ /* Chat message styling */
206
+ .stChatMessage {
207
+ background-color: white;
208
+ border-radius: 10px;
209
+ padding: 15px;
210
+ margin: 10px 0;
211
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
212
+ }
213
+
214
+ /* Info box styling */
215
+ .stInfo {
216
+ background-color: #e3f2fd;
217
+ border-left: 5px solid #2196f3;
218
+ }
219
+
220
+ /* Success box styling */
221
+ .stSuccess {
222
+ background-color: #e8f5e9;
223
+ border-left: 5px solid #4caf50;
224
+ }
225
+
226
+ /* Questions table styling */
227
+ table {
228
+ background-color: white;
229
+ border-radius: 10px;
230
+ overflow: hidden;
231
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
232
+ }
233
+
234
+ th {
235
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
236
+ color: white;
237
+ padding: 15px;
238
+ }
239
+
240
+ td {
241
+ padding: 12px;
242
+ border-bottom: 1px solid #e0e0e0;
243
+ }
244
+
245
+ /* Sidebar styling */
246
+ .css-1d391kg {
247
+ background-color: #f8f9fa;
248
+ }
249
+ </style>
250
+ """, unsafe_allow_html=True)
251
+
252
+ st.markdown("""
253
+ <div class="main-header">
254
+ <h1>📚 Study Companion</h1>
255
+ <p>Your AI-powered learning assistant</p>
256
+ </div>
257
+ """, unsafe_allow_html=True)
258
+
259
+ if st.session_state.pdf_text is None:
260
+ st.info("Please upload a PDF from the sidebar to begin.")
261
+ else:
262
+ if mode == "Chat":
263
+ st.header("💬 Chat with Your Study Companion")
264
+ st.markdown("""
265
+ <style>
266
+ .chat-container {
267
+ background: white;
268
+ border-radius: 10px;
269
+ padding: 20px;
270
+ margin: 15px 0;
271
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
272
+ }
273
+ </style>
274
+ """, unsafe_allow_html=True)
275
+
276
+ # Display persistent chat history
277
+ for msg in st.session_state.chat_history:
278
+ st.chat_message(msg["role"]).write(msg["content"])
279
+
280
+ user_question = st.chat_input("💭 Ask a question about the document...")
281
+ if user_question:
282
+ st.session_state.chat_history.append({"role": "user", "content": user_question})
283
+ st.chat_message("user").write(user_question)
284
+ with st.spinner("🤔 Thinking..."):
285
+ response = chat_with_document(st.session_state.pdf_text, st.session_state.chat_history, user_question)
286
+ st.session_state.chat_history.append({"role": "assistant", "content": response})
287
+ st.chat_message("assistant").write(response)
288
+
289
+ # Add a clear chat button
290
+ if len(st.session_state.chat_history) > 1:
291
+ if st.button("🗑️ Clear Chat History"):
292
+ st.session_state.chat_history = [{"role": "assistant", "content": "Hi, how can I help you with your study material?"}]
293
+ st.rerun()
294
+
295
+ elif mode == "Test Your Knowledge":
296
+ st.header("📝 Test Your Knowledge")
297
+ st.markdown("""
298
+ <style>
299
+ .question-container {
300
+ background: white;
301
+ border-radius: 10px;
302
+ padding: 20px;
303
+ margin: 15px 0;
304
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
305
+ }
306
+ </style>
307
+ """, unsafe_allow_html=True)
308
+
309
+ if num_questions is None:
310
+ st.info("Please specify the number of questions in the sidebar.")
311
+ else:
312
+ if st.button("📋 Generate Questions", use_container_width=True, type="primary"):
313
+ with st.spinner("✨ Generating questions..."):
314
+ questions_output = generate_questions_from_text(st.session_state.pdf_text, num_questions)
315
+ st.session_state.questions_table = questions_output
316
+
317
+ if st.session_state.questions_table:
318
+ st.markdown('<div class="question-container">', unsafe_allow_html=True)
319
+ st.markdown(st.session_state.questions_table)
320
+ st.markdown('</div>', unsafe_allow_html=True)
321
+
322
+ # Download button for questions
323
+ st.download_button(
324
+ label="📥 Download Questions",
325
+ data=st.session_state.questions_table,
326
+ file_name="study_questions.md",
327
+ mime="text/markdown"
328
+ )
329
+ else:
330
+ st.info("💡 Click 'Generate Questions' to create a quiz based on your document.")
331
+
332
+ elif mode == "Flashcards":
333
+ st.header("🎴 Interactive Flashcards")
334
+
335
+ # Custom CSS for flashcard styling
336
+ st.markdown("""
337
+ <style>
338
+ .flashcard-container {
339
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
340
+ border-radius: 15px;
341
+ padding: 40px;
342
+ margin: 20px 0;
343
+ box-shadow: 0 10px 30px rgba(0,0,0,0.3);
344
+ min-height: 250px;
345
+ display: flex;
346
+ align-items: center;
347
+ justify-content: center;
348
+ text-align: center;
349
+ transition: transform 0.3s ease;
350
+ }
351
+ .flashcard-container:hover {
352
+ transform: translateY(-5px);
353
+ }
354
+ .flashcard-question {
355
+ color: white;
356
+ font-size: 24px;
357
+ font-weight: bold;
358
+ margin-bottom: 20px;
359
+ }
360
+ .flashcard-answer {
361
+ background: rgba(255,255,255,0.95);
362
+ border-radius: 10px;
363
+ padding: 25px;
364
+ margin-top: 20px;
365
+ color: #333;
366
+ font-size: 18px;
367
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
368
+ }
369
+ .score-card {
370
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
371
+ border-radius: 10px;
372
+ padding: 20px;
373
+ color: white;
374
+ font-size: 20px;
375
+ font-weight: bold;
376
+ text-align: center;
377
+ margin: 20px 0;
378
+ }
379
+ .progress-bar-container {
380
+ background: #e0e0e0;
381
+ border-radius: 10px;
382
+ height: 20px;
383
+ margin: 20px 0;
384
+ overflow: hidden;
385
+ }
386
+ .progress-bar {
387
+ background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
388
+ height: 100%;
389
+ transition: width 0.3s ease;
390
+ }
391
+ .card-number {
392
+ color: white;
393
+ font-size: 16px;
394
+ margin-bottom: 10px;
395
+ opacity: 0.9;
396
+ }
397
+ .stButton > button {
398
+ border-radius: 8px;
399
+ font-weight: 600;
400
+ padding: 10px 24px;
401
+ transition: all 0.3s ease;
402
+ }
403
+ .stButton > button:hover {
404
+ transform: scale(1.05);
405
+ box-shadow: 0 4px 12px rgba(0,0,0,0.2);
406
+ }
407
+ </style>
408
+ """, unsafe_allow_html=True)
409
+
410
+ # Sidebar controls for flashcards
411
+ with st.sidebar:
412
+ st.markdown("---")
413
+ st.subheader("🎴 Flashcard Options")
414
+ shuffle_option = st.checkbox("Shuffle cards", value=st.session_state.shuffle_cards)
415
+ if shuffle_option != st.session_state.shuffle_cards:
416
+ st.session_state.shuffle_cards = shuffle_option
417
+ if st.session_state.flashcards and st.session_state.flashcard_keys:
418
+ if shuffle_option:
419
+ st.session_state.flashcard_keys = list(st.session_state.flashcards.keys())
420
+ random.shuffle(st.session_state.flashcard_keys)
421
+ else:
422
+ st.session_state.flashcard_keys = list(st.session_state.flashcards.keys())
423
+
424
+ if num_flashcards is None:
425
+ st.info("Please specify the number of flashcards in the sidebar.")
426
+ else:
427
+ col1, col2 = st.columns([3, 1])
428
+ with col1:
429
+ if st.button("🎯 Generate Flashcards", use_container_width=True):
430
+ with st.spinner("✨ Creating your flashcards..."):
431
+ flashcards = generate_flashcards_from_text(st.session_state.pdf_text, num_flashcards)
432
+ if flashcards:
433
+ st.session_state.flashcards = flashcards
434
+ st.session_state.flashcard_keys = list(flashcards.keys())
435
+ if st.session_state.shuffle_cards:
436
+ random.shuffle(st.session_state.flashcard_keys)
437
+ st.session_state.current_card = 0
438
+ st.session_state.score = 0
439
+ st.session_state.show_answer = False
440
+ st.session_state.user_answers = {}
441
+ st.success("✅ Flashcards generated successfully!")
442
+ st.rerun()
443
+ else:
444
+ st.error("Failed to generate flashcards. Please try again.")
445
+
446
+ with col2:
447
+ if st.session_state.flashcards and st.button("🔄 Reset", use_container_width=True):
448
+ st.session_state.current_card = 0
449
+ st.session_state.score = 0
450
+ st.session_state.show_answer = False
451
+ st.session_state.user_answers = {}
452
+ st.rerun()
453
+
454
+ if not st.session_state.flashcards:
455
+ st.info("💡 No flashcards available. Click 'Generate Flashcards' to create a study set based on your document.")
456
+ else:
457
+ total_cards = len(st.session_state.flashcards)
458
+
459
+ if st.session_state.current_card >= total_cards:
460
+ # Completion screen
461
+ st.balloons()
462
+ st.markdown(f"""
463
+ <div class="score-card">
464
+ 🎉 Congratulations! You've completed all flashcards!<br>
465
+ Final Score: {st.session_state.score} / {total_cards} ({int(st.session_state.score/total_cards*100)}%)
466
+ </div>
467
+ """, unsafe_allow_html=True)
468
+
469
+ # Show review of incorrect answers
470
+ if st.session_state.user_answers:
471
+ st.subheader("📝 Review Your Answers")
472
+ for i, (q, is_correct) in enumerate(st.session_state.user_answers.items(), 1):
473
+ if not is_correct:
474
+ with st.expander(f"❌ Card {i}: {q[:50]}..."):
475
+ st.write(f"**Question:** {q}")
476
+ st.write(f"**Answer:** {st.session_state.flashcards[q]}")
477
+
478
+ col1, col2 = st.columns(2)
479
+ with col1:
480
+ if st.button("🔄 Practice Again", use_container_width=True):
481
+ st.session_state.current_card = 0
482
+ st.session_state.score = 0
483
+ st.session_state.show_answer = False
484
+ st.session_state.user_answers = {}
485
+ if st.session_state.shuffle_cards:
486
+ random.shuffle(st.session_state.flashcard_keys)
487
+ st.rerun()
488
+ with col2:
489
+ if st.button("📚 New Set", use_container_width=True):
490
+ st.session_state.flashcards = {}
491
+ st.session_state.flashcard_keys = []
492
+ st.session_state.current_card = 0
493
+ st.session_state.score = 0
494
+ st.session_state.show_answer = False
495
+ st.session_state.user_answers = {}
496
+ st.rerun()
497
+ else:
498
+ # Progress bar
499
+ progress = (st.session_state.current_card / total_cards) * 100
500
+ st.markdown(f"""
501
+ <div class="progress-bar-container">
502
+ <div class="progress-bar" style="width: {progress}%"></div>
503
+ </div>
504
+ """, unsafe_allow_html=True)
505
+
506
+ # Display current card
507
+ current_key = st.session_state.flashcard_keys[st.session_state.current_card]
508
+ current_answer = st.session_state.flashcards[current_key]
509
+
510
+ st.markdown(f"""
511
+ <div class="flashcard-container">
512
+ <div>
513
+ <div class="card-number">Card {st.session_state.current_card + 1} of {total_cards}</div>
514
+ <div class="flashcard-question">{current_key}</div>
515
+ </div>
516
+ </div>
517
+ """, unsafe_allow_html=True)
518
+
519
+ # Show/Hide answer button
520
+ if not st.session_state.show_answer:
521
+ if st.button("🔍 Show Answer", use_container_width=True, key="show_btn"):
522
+ st.session_state.show_answer = True
523
+ st.rerun()
524
+ else:
525
+ st.markdown(f"""
526
+ <div class="flashcard-answer">
527
+ <strong>Answer:</strong><br><br>
528
+ {current_answer}
529
+ </div>
530
+ """, unsafe_allow_html=True)
531
+
532
+ st.markdown("### Did you get it right?")
533
+ col1, col2, col3 = st.columns([1, 1, 1])
534
+
535
+ with col1:
536
+ if st.button("✅ Got it!", use_container_width=True, type="primary"):
537
+ st.session_state.score += 1
538
+ st.session_state.user_answers[current_key] = True
539
+ st.session_state.current_card += 1
540
+ st.session_state.show_answer = False
541
+ st.rerun()
542
+
543
+ with col2:
544
+ if st.button("❌ Missed it", use_container_width=True):
545
+ st.session_state.user_answers[current_key] = False
546
+ st.session_state.current_card += 1
547
+ st.session_state.show_answer = False
548
+ st.rerun()
549
+
550
+ with col3:
551
+ if st.button("⏭️ Skip", use_container_width=True):
552
+ st.session_state.current_card += 1
553
+ st.session_state.show_answer = False
554
+ st.rerun()
555
+
556
+ # Current score display
557
+ st.markdown(f"""
558
+ <div class="score-card">
559
+ Current Score: {st.session_state.score} / {st.session_state.current_card}
560
+ {f"({int(st.session_state.score/st.session_state.current_card*100)}%)" if st.session_state.current_card > 0 else ""}
561
+ </div>
562
+ """, unsafe_allow_html=True)
563
+
564
+
565
+
566
+
567
+
568
+ # # Import the CrewAI flashcard module (modified below to remove page range)
569
+ # from crewai_flashcard import generate_flashcards
570
+
571
+ # # ---------------------------
572
+ # # Helper Function: Extract text from PDF
573
+ # # ---------------------------
574
+ # def extract_text(uploaded_file):
575
+ # # Ensure file size is less than 10MB
576
+ # uploaded_file.seek(0, os.SEEK_END)
577
+ # if uploaded_file.tell() > 10 * 1024 * 1024:
578
+ # st.error("File exceeds 10MB limit.")
579
+ # return ""
580
+ # uploaded_file.seek(0)
581
+ # pdf_reader = PdfReader(uploaded_file)
582
+ # text = ""
583
+ # for page in pdf_reader.pages:
584
+ # page_text = page.extract_text()
585
+ # if page_text:
586
+ # text += page_text + "\n"
587
+ # return text
588
+
589
+ # # ---------------------------
590
+ # # OpenAI Response Functions
591
+ # # ---------------------------
592
+ # def generate_summary_from_text(text):
593
+ # prompt = (
594
+ # f"Summarize the following document in a concise manner, highlighting the key points that a student should know:\n\n{text}"
595
+ # )
596
+ # messages = [
597
+ # {"role": "system", "content": "You are an educational assistant."},
598
+ # {"role": "user", "content": prompt}
599
+ # ]
600
+ # completion = client.chat.completions.create(
601
+ # model="gpt-4o-mini",
602
+ # messages=messages
603
+ # )
604
+ # return completion.choices[0].message.content.strip()
605
+
606
+ # def chat_with_document(text, conversation_history, user_query):
607
+ # messages = conversation_history + [
608
+ # {"role": "user", "content": f"Based on the following document:\n\n{text}\n\nQuestion: {user_query}"}
609
+ # ]
610
+ # completion = client.chat.completions.create(
611
+ # model="gpt-4o-mini",
612
+ # messages=messages
613
+ # )
614
+ # return completion.choices[0].message.content.strip()
615
+
616
+ # def generate_questions_from_text(text, num_questions):
617
+ # prompt = (
618
+ # f"Generate {num_questions} study questions with answers based on the following document. "
619
+ # "Return the output as a table in CSV format with two columns: 'Question' and 'Answer'.\n\nDocument:\n\n{text}"
620
+ # )
621
+ # messages = [
622
+ # {"role": "system", "content": "You are an educational assistant that generates study questions."},
623
+ # {"role": "user", "content": prompt}
624
+ # ]
625
+ # completion = client.chat.completions.create(
626
+ # model="gpt-4o-mini",
627
+ # messages=messages
628
+ # )
629
+ # # Expecting CSV output (with header: Question,Answer)
630
+ # return completion.choices[0].message.content.strip()
631
+
632
+ # # ---------------------------
633
+ # # Sidebar: File Upload & Mode Selection
634
+ # # ---------------------------
635
+ # st.sidebar.title("Study Companion Setup")
636
+
637
+ # uploaded_pdf = st.sidebar.file_uploader("Upload your study PDF (max 10MB)", type="pdf")
638
+ # mode = st.sidebar.radio("Select Mode", ("Chat", "Test Your Knowledge", "Flashcards"))
639
+
640
+ # # For Test Your Knowledge: number of questions (max 50)
641
+ # num_questions = None
642
+ # if mode == "Test Your Knowledge":
643
+ # num_questions = st.sidebar.number_input("Number of questions to generate (max 50):", min_value=1, max_value=50, value=10, step=1)
644
+ # if st.sidebar.button("Generate Questions"):
645
+ # st.session_state.gen_questions = True
646
+
647
+ # # For Flashcards: number of flashcards (max 5)
648
+ # num_flashcards = None
649
+ # if mode == "Flashcards":
650
+ # num_flashcards = st.sidebar.number_input("Number of flashcards to generate (max 5):", min_value=1, max_value=5, value=3, step=1)
651
+ # if st.sidebar.button("Generate Flashcards"):
652
+ # st.session_state.gen_flashcards = True
653
+
654
+ # # ---------------------------
655
+ # # Session State Initialization
656
+ # # ---------------------------
657
+ # if "pdf_text" not in st.session_state:
658
+ # st.session_state.pdf_text = None
659
+ # if "summary" not in st.session_state:
660
+ # st.session_state.summary = None
661
+ # if "chat_history" not in st.session_state:
662
+ # st.session_state.chat_history = [{"role": "assistant", "content": "Hi, how can I help you with your study material?"}]
663
+ # if "questions_table" not in st.session_state:
664
+ # st.session_state.questions_table = None
665
+ # if "flashcards" not in st.session_state:
666
+ # st.session_state.flashcards = {}
667
+ # if "current_card" not in st.session_state:
668
+ # st.session_state.current_card = 0
669
+ # if "score" not in st.session_state:
670
+ # st.session_state.score = 0
671
+ # if "show_answer" not in st.session_state:
672
+ # st.session_state.show_answer = False
673
+
674
+ # # ---------------------------
675
+ # # Process PDF Upload
676
+ # # ---------------------------
677
+ # if uploaded_pdf is not None:
678
+ # with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
679
+ # tmp.write(uploaded_pdf.read())
680
+ # st.session_state.pdf_file_path = tmp.name
681
+ # st.session_state.pdf_text = extract_text(uploaded_pdf)
682
+ # if st.session_state.pdf_text:
683
+ # st.sidebar.success("PDF uploaded and processed successfully!")
684
+ # else:
685
+ # st.sidebar.error("Failed to extract text from the PDF.")
686
+
687
+ # # ---------------------------
688
+ # # Main Area: Mode-Based Display (using side menu)
689
+ # # ---------------------------
690
+ # st.title("Study Companion: PDF-based Learning")
691
+
692
+ # if st.session_state.pdf_text is None:
693
+ # st.info("Please upload a PDF from the sidebar to begin.")
694
+ # else:
695
+ # if mode == "Chat":
696
+ # st.header("Chat with Your Study Companion")
697
+ # for msg in st.session_state.chat_history:
698
+ # st.chat_message(msg["role"]).write(msg["content"])
699
+ # user_question = st.chat_input("Ask a question about the document:")
700
+ # if user_question:
701
+ # st.session_state.chat_history.append({"role": "user", "content": user_question})
702
+ # st.chat_message("user").write(user_question)
703
+ # with st.spinner("Processing your question..."):
704
+ # response = chat_with_document(st.session_state.pdf_text, st.session_state.chat_history, user_question)
705
+ # st.session_state.chat_history.append({"role": "assistant", "content": response})
706
+ # st.chat_message("assistant").write(response)
707
+
708
+ # elif mode == "Test Your Knowledge":
709
+ # st.header("Test Your Knowledge")
710
+ # if num_questions is None or not st.session_state.get("gen_questions", False):
711
+ # st.info("Enter the number of questions and press 'Generate Questions' from the sidebar.")
712
+ # else:
713
+ # with st.spinner("Generating questions..."):
714
+ # questions_csv = generate_questions_from_text(st.session_state.pdf_text, num_questions)
715
+ # # Convert CSV output into a table (assuming header row "Question,Answer")
716
+ # try:
717
+ # lines = questions_csv.splitlines()
718
+ # if len(lines) < 2:
719
+ # st.error("Failed to generate questions properly.")
720
+ # else:
721
+ # header = lines[0].split(",")
722
+ # data = [line.split(",") for line in lines[1:]]
723
+ # st.table(data, headers=header)
724
+ # st.session_state.questions_table = data
725
+ # except Exception as e:
726
+ # st.error(f"Error processing questions: {e}")
727
+
728
+ # elif mode == "Flashcards":
729
+ # st.header("Practice Flashcards")
730
+ # if not st.session_state.get("gen_flashcards", False):
731
+ # st.info("Enter the number of flashcards and press 'Generate Flashcards' from the sidebar.")
732
+ # else:
733
+ # if st.button("Reset Flashcards"):
734
+ # st.session_state.flashcards = {}
735
+ # st.session_state.current_card = 0
736
+ # st.session_state.score = 0
737
+ # st.session_state.show_answer = False
738
+ # st.session_state.gen_flashcards = False
739
+ # if st.session_state.get("gen_flashcards", False):
740
+ # # Generate flashcards using the CrewAI module (which returns a Python dictionary)
741
+ # flashcards = generate_flashcards(st.session_state.pdf_file_path, num_flashcards)
742
+ # st.session_state.flashcards = flashcards
743
+ # st.session_state.current_card = 0
744
+ # st.session_state.score = 0
745
+ # st.session_state.show_answer = False
746
+ # st.success("Flashcards generated successfully!")
747
+ # st.session_state.gen_flashcards = False # reset flag after generation
748
+
749
+ # if not st.session_state.flashcards:
750
+ # st.info("No flashcards available. Click the 'Generate Flashcards' button in the sidebar.")
751
+ # else:
752
+ # total_cards = len(st.session_state.flashcards)
753
+ # if st.session_state.current_card >= total_cards:
754
+ # st.success(f"You've completed all flashcards! Final Score: {st.session_state.score} / {total_cards}")
755
+ # st.info("Restart the session or generate new flashcards from the sidebar.")
756
+ # else:
757
+ # flashcards = st.session_state.flashcards
758
+ # current_keys = list(flashcards.keys())
759
+ # current_question = current_keys[st.session_state.current_card]
760
+ # current_answer = flashcards[current_question]
761
+ # st.write(f"**Question:** {current_question}")
762
+ # if st.button("Show Answer"):
763
+ # st.session_state.show_answer = True
764
+ # if st.session_state.show_answer:
765
+ # st.write(f"**Answer:** {current_answer}")
766
+ # col1, col2 = st.columns(2)
767
+ # with col1:
768
+ # if st.button("Correct"):
769
+ # st.session_state.score += 1
770
+ # st.success("Correct!")
771
+ # with col2:
772
+ # if st.button("Wrong"):
773
+ # st.error("Incorrect!")
774
+ # if st.button("Next Card"):
775
+ # st.session_state.current_card += 1
776
+ # st.session_state.show_answer = False
777
+ # st.rerun()
778
+ # st.write(f"**Current Score:** {st.session_state.score} / {total_cards}")
779
+
780
+
781
+
782
+
783
+ ######################################################################################################
784
+
785
+
786
+ # # ---------------------------
787
+ # # Helper Function: Extract text from PDF
788
+ # # ---------------------------
789
+ # def extract_text(uploaded_file):
790
+ # pdf_reader = PdfReader(uploaded_file)
791
+ # text = ""
792
+ # for page in pdf_reader.pages:
793
+ # page_text = page.extract_text()
794
+ # if page_text:
795
+ # text += page_text
796
+ # return text
797
+
798
+ # # ---------------------------
799
+ # # OpenAI Response Functions (using new style)
800
+ # # ---------------------------
801
+ # def generate_summary_from_text(text):
802
+ # prompt = (
803
+ # f"Summarize the following document in a concise manner, "
804
+ # "highlighting the key points that a student should know:\n\n{text}"
805
+ # )
806
+ # messages = [
807
+ # {"role": "system", "content": "You are an educational assistant."},
808
+ # {"role": "user", "content": prompt}
809
+ # ]
810
+ # completion = client.chat.completions.create(
811
+ # model="gpt-4o-mini",
812
+ # messages=messages
813
+ # )
814
+ # return completion.choices[0].message.content.strip()
815
+
816
+ # def chat_with_document(text, conversation_history, user_query):
817
+ # messages = conversation_history + [
818
+ # {"role": "user", "content": f"Based on the following document:\n\n{text}\n\nQuestion: {user_query}"}
819
+ # ]
820
+ # completion = client.chat.completions.create(
821
+ # model="gpt-4o-mini",
822
+ # messages=messages
823
+ # )
824
+ # return completion.choices[0].message.content.strip()
825
+
826
+ # def generate_flashcards_from_text(text, num_cards):
827
+ # prompt = (
828
+ # f"Generate {num_cards} flashcards based on the following document. \n\nDocument:\n\n{text} "
829
+ # "Return a Python dictionary where each key is a flashcard question and its corresponding value is the answer. "
830
+ # #"Do not include any additional text.\n\nDocument:\n\n{text}"
831
+ # )
832
+ # messages = [
833
+ # {"role": "system", "content": "You are an educational assistant that creates study flashcards."},
834
+ # {"role": "user", "content": prompt}
835
+ # ]
836
+ # completion = client.chat.completions.create(
837
+ # model="gpt-4o-mini",
838
+ # messages=messages
839
+ # )
840
+ # output = completion.choices[0].message.content.strip()
841
+ # try:
842
+ # # Use literal_eval to safely evaluate the string as a Python dictionary.
843
+ # flashcards = literal_eval(output)
844
+ # if isinstance(flashcards, dict):
845
+ # return flashcards
846
+ # else:
847
+ # return {}
848
+ # except Exception as e:
849
+ # st.error(f"Error parsing flashcards: {e}")
850
+ # return {}
851
+
852
+ # # ---------------------------
853
+ # # Sidebar: File Upload & Mode Selection
854
+ # # ---------------------------
855
+ # st.sidebar.title("Study Companion Setup")
856
+
857
+ # uploaded_pdf = st.sidebar.file_uploader("Upload your study PDF", type="pdf")
858
+ # mode = st.sidebar.radio("Select Mode", ("Summary", "Chat", "Flashcards"))
859
+
860
+ # num_flashcards = None
861
+ # if mode == "Flashcards":
862
+ # num_flashcards = st.sidebar.number_input("Number of flashcards to generate:", min_value=1, max_value=20, value=5, step=1)
863
+
864
+ # # ---------------------------
865
+ # # Session State Initialization
866
+ # # ---------------------------
867
+ # if "pdf_text" not in st.session_state:
868
+ # st.session_state.pdf_text = None
869
+ # if "summary" not in st.session_state:
870
+ # st.session_state.summary = None
871
+ # if "chat_history" not in st.session_state:
872
+ # st.session_state.chat_history = [{"role": "assistant", "content": "Hi, how can I help you with your study material?"}]
873
+ # if "flashcards" not in st.session_state:
874
+ # st.session_state.flashcards = {}
875
+ # if "current_card" not in st.session_state:
876
+ # st.session_state.current_card = 0
877
+ # if "score" not in st.session_state:
878
+ # st.session_state.score = 0
879
+ # if "show_answer" not in st.session_state:
880
+ # st.session_state.show_answer = False
881
+
882
+ # # ---------------------------
883
+ # # Process PDF Upload
884
+ # # ---------------------------
885
+ # if uploaded_pdf is not None:
886
+ # with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
887
+ # tmp.write(uploaded_pdf.read())
888
+ # st.session_state.pdf_file_path = tmp.name
889
+ # st.session_state.pdf_text = extract_text(uploaded_pdf)
890
+ # st.sidebar.success("PDF uploaded and processed successfully!")
891
+
892
+ # # ---------------------------
893
+ # # Main Area: Mode-Based Display
894
+ # # ---------------------------
895
+ # st.title("Study Companion: PDF-based Learning")
896
+
897
+ # if st.session_state.pdf_text is None:
898
+ # st.info("Please upload a PDF from the sidebar to begin.")
899
+ # else:
900
+ # if mode == "Summary":
901
+ # st.header("Summary & Key Points")
902
+ # if st.session_state.summary is None:
903
+ # with st.spinner("Generating summary..."):
904
+ # st.session_state.summary = generate_summary_from_text(st.session_state.pdf_text)
905
+ # st.write(st.session_state.summary)
906
+
907
+ # elif mode == "Chat":
908
+ # st.header("Chat with Your Study Companion")
909
+ # for msg in st.session_state.chat_history:
910
+ # st.chat_message(msg["role"]).write(msg["content"])
911
+ # user_question = st.chat_input("Ask a question about the document:")
912
+ # if user_question:
913
+ # st.session_state.chat_history.append({"role": "user", "content": user_question})
914
+ # st.chat_message("user").write(user_question)
915
+ # with st.spinner("Processing your question..."):
916
+ # response = chat_with_document(st.session_state.pdf_text, st.session_state.chat_history, user_question)
917
+ # st.session_state.chat_history.append({"role": "assistant", "content": response})
918
+ # st.chat_message("assistant").write(response)
919
+
920
+ # elif mode == "Flashcards":
921
+ # st.header("Practice Flashcards")
922
+ # if st.button("Generate Flashcards"):
923
+ # with st.spinner("Generating flashcards..."):
924
+ # flashcards = generate_flashcards_from_text(st.session_state.pdf_text, num_flashcards)
925
+ # st.session_state.flashcards = flashcards
926
+ # st.session_state.current_card = 0
927
+ # st.session_state.score = 0
928
+ # st.session_state.show_answer = False
929
+ # st.success("Flashcards generated successfully!")
930
+
931
+ # if not st.session_state.flashcards:
932
+ # st.info("No flashcards available. Click the button above to generate flashcards.")
933
+ # else:
934
+ # total_cards = len(st.session_state.flashcards)
935
+ # if st.session_state.current_card >= total_cards:
936
+ # st.success(f"You've completed all flashcards! Final Score: {st.session_state.score} / {total_cards}")
937
+ # st.info("Restart the session or generate new flashcards from the sidebar.")
938
+ # else:
939
+ # flashcards = st.session_state.flashcards
940
+ # current_keys = list(flashcards.keys())
941
+ # current_question = current_keys[st.session_state.current_card]
942
+ # current_answer = flashcards[current_question]
943
+ # st.write(f"**Question:** {current_question}")
944
+ # if st.button("Show Answer"):
945
+ # st.session_state.show_answer = True
946
+ # if st.session_state.show_answer:
947
+ # st.write(f"**Answer:** {current_answer}")
948
+ # col1, col2 = st.columns(2)
949
+ # with col1:
950
+ # if st.button("Correct"):
951
+ # st.session_state.score += 1
952
+ # st.success("Correct!")
953
+ # with col2:
954
+ # if st.button("Wrong"):
955
+ # st.error("Incorrect!")
956
+ # if st.button("Next Card"):
957
+ # st.session_state.current_card += 1
958
+ # st.session_state.show_answer = False
959
+ # st.rerun()
960
+ # st.write(f"**Current Score:** {st.session_state.score} / {total_cards}")
961
+
962
+
963
+
964
+
965
+ # # ---------------------------
966
+ # # Helper Function: Extract text from PDF
967
+ # # ---------------------------
968
+ # def extract_text(uploaded_file):
969
+ # pdf_reader = PdfReader(uploaded_file)
970
+ # text = ""
971
+ # for page in pdf_reader.pages:
972
+ # page_text = page.extract_text()
973
+ # if page_text:
974
+ # text += page_text
975
+ # return text
976
+
977
+ # # ---------------------------
978
+ # # OpenAI Response Functions (using new style)
979
+ # # ---------------------------
980
+ # def generate_summary_from_text(text):
981
+ # prompt = (
982
+ # f"Summarize the following document in a concise manner, "
983
+ # "highlighting the key points that a student should know:\n\n{text}"
984
+ # )
985
+ # messages = [
986
+ # {"role": "system", "content": "You are an educational assistant."},
987
+ # {"role": "user", "content": prompt}
988
+ # ]
989
+ # completion = client.chat.completions.create(
990
+ # model="gpt-4o-mini",
991
+ # messages=messages
992
+ # )
993
+ # return completion.choices[0].message.content.strip()
994
+
995
+ # def chat_with_document(text, conversation_history, user_query):
996
+ # # Build a message list that includes the conversation history plus the new query with context.
997
+ # messages = conversation_history + [
998
+ # {"role": "user", "content": f"Based on the following document:\n\n{text}\n\nQuestion: {user_query}"}
999
+ # ]
1000
+ # completion = client.chat.completions.create(
1001
+ # model="gpt-4o-mini",
1002
+ # messages=messages
1003
+ # )
1004
+ # return completion.choices[0].message.content.strip()
1005
+
1006
+ # def generate_flashcards_from_text(text, num_cards):
1007
+ # prompt = (
1008
+ # f"Generate {num_cards} flashcards based on the following document. "
1009
+ # "Return a Python dictionary (in valid JSON format) where each key is a flashcard question and its value is the corresponding answer. "
1010
+ # f"Document:\n\n{text}"
1011
+ # )
1012
+ # messages = [
1013
+ # {"role": "system", "content": "You are an educational assistant that creates study flashcards."},
1014
+ # {"role": "user", "content": prompt}
1015
+ # ]
1016
+ # completion = client.chat.completions.create(
1017
+ # model="gpt-4o-mini",
1018
+ # messages=messages
1019
+ # )
1020
+ # output = completion.choices[0].message.content.strip()
1021
+ # try:
1022
+ # flashcards = json.loads(output)
1023
+ # if isinstance(flashcards, dict):
1024
+ # return flashcards
1025
+ # else:
1026
+ # return {}
1027
+ # except Exception as e:
1028
+ # st.error(f"Error parsing flashcards: {e}")
1029
+ # return {}
1030
+
1031
+ # # ---------------------------
1032
+ # # Sidebar: File Upload & Mode Selection
1033
+ # # ---------------------------
1034
+ # st.sidebar.title("Study Companion Setup")
1035
+
1036
+ # uploaded_pdf = st.sidebar.file_uploader("Upload your study PDF", type="pdf")
1037
+ # mode = st.sidebar.radio("Select Mode", ("Summary", "Chat", "Flashcards"))
1038
+
1039
+ # # For Flashcards, allow user to input number of flashcards
1040
+ # num_flashcards = None
1041
+ # if mode == "Flashcards":
1042
+ # num_flashcards = st.sidebar.number_input("Number of flashcards to generate:", min_value=1, max_value=20, value=5, step=1)
1043
+
1044
+ # # ---------------------------
1045
+ # # Session State Initialization
1046
+ # # ---------------------------
1047
+ # if "pdf_text" not in st.session_state:
1048
+ # st.session_state.pdf_text = None
1049
+ # if "summary" not in st.session_state:
1050
+ # st.session_state.summary = None
1051
+ # if "chat_history" not in st.session_state:
1052
+ # st.session_state.chat_history = [{"role": "assistant", "content": "Hi, how can I help you with your study material?"}]
1053
+ # if "flashcards" not in st.session_state:
1054
+ # st.session_state.flashcards = {}
1055
+ # if "current_card" not in st.session_state:
1056
+ # st.session_state.current_card = 0
1057
+ # if "score" not in st.session_state:
1058
+ # st.session_state.score = 0
1059
+ # if "show_answer" not in st.session_state:
1060
+ # st.session_state.show_answer = False
1061
+
1062
+ # # ---------------------------
1063
+ # # Process PDF Upload
1064
+ # # ---------------------------
1065
+ # if uploaded_pdf is not None:
1066
+ # with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
1067
+ # tmp.write(uploaded_pdf.read())
1068
+ # pdf_file_path = tmp.name
1069
+ # # Extract text from the PDF (all pages)
1070
+ # st.session_state.pdf_text = extract_text(pdf_file_path)
1071
+ # st.sidebar.success("PDF uploaded and processed successfully!")
1072
+
1073
+ # # ---------------------------
1074
+ # # Main Area: Mode-Based Display
1075
+ # # ---------------------------
1076
+ # st.title("Study Companion: PDF-based Learning")
1077
+
1078
+ # if st.session_state.pdf_text is None:
1079
+ # st.info("Please upload a PDF from the sidebar to begin.")
1080
+ # else:
1081
+ # if mode == "Summary":
1082
+ # st.header("Summary & Key Points")
1083
+ # if st.session_state.summary is None:
1084
+ # with st.spinner("Generating summary..."):
1085
+ # st.session_state.summary = generate_summary_from_text(st.session_state.pdf_text)
1086
+ # st.write(st.session_state.summary)
1087
+
1088
+ # elif mode == "Chat":
1089
+ # st.header("Chat with Your Study Companion")
1090
+ # # Display persistent chat history
1091
+ # for msg in st.session_state.chat_history:
1092
+ # st.chat_message(msg["role"]).write(msg["content"])
1093
+ # user_question = st.chat_input("Ask a question about the document:")
1094
+ # if user_question:
1095
+ # st.session_state.chat_history.append({"role": "user", "content": user_question})
1096
+ # st.chat_message("user").write(user_question)
1097
+ # with st.spinner("Processing your question..."):
1098
+ # response = chat_with_document(st.session_state.pdf_text, st.session_state.chat_history, user_question)
1099
+ # st.session_state.chat_history.append({"role": "assistant", "content": response})
1100
+ # st.chat_message("assistant").write(response)
1101
+
1102
+ # elif mode == "Flashcards":
1103
+ # st.header("Practice Flashcards")
1104
+ # # Provide a button to generate flashcards on demand.
1105
+ # if st.button("Generate Flashcards"):
1106
+ # with st.spinner("Generating flashcards..."):
1107
+ # flashcards = generate_flashcards_from_text(st.session_state.pdf_text, num_flashcards)
1108
+ # st.session_state.flashcards = flashcards
1109
+ # st.session_state.current_card = 0
1110
+ # st.session_state.score = 0
1111
+ # st.session_state.show_answer = False
1112
+ # st.success("Flashcards generated successfully!")
1113
+
1114
+ # if not st.session_state.flashcards:
1115
+ # st.info("No flashcards available. Click the button above to generate flashcards.")
1116
+ # else:
1117
+ # total_cards = len(st.session_state.flashcards)
1118
+ # if st.session_state.current_card >= total_cards:
1119
+ # st.success(f"You've completed all flashcards! Final Score: {st.session_state.score} / {total_cards}")
1120
+ # st.info("Restart the session or generate new flashcards from the sidebar.")
1121
+ # else:
1122
+ # flashcards = st.session_state.flashcards
1123
+ # # Get the current flashcard key-value pair.
1124
+ # current_keys = list(flashcards.keys())
1125
+ # current_key = current_keys[st.session_state.current_card]
1126
+ # current_answer = flashcards[current_key]
1127
+ # st.write(f"**Question:** {current_key}")
1128
+ # if st.button("Show Answer"):
1129
+ # st.session_state.show_answer = True
1130
+ # if st.session_state.show_answer:
1131
+ # st.write(f"**Answer:** {current_answer}")
1132
+ # col1, col2 = st.columns(2)
1133
+ # with col1:
1134
+ # if st.button("Correct"):
1135
+ # st.session_state.score += 1
1136
+ # st.success("Correct!")
1137
+ # with col2:
1138
+ # if st.button("Wrong"):
1139
+ # st.error("Incorrect!")
1140
+ # if st.button("Next Card"):
1141
+ # st.session_state.current_card += 1
1142
+ # st.session_state.show_answer = False
1143
+ # st.rerun()
1144
+ # st.write(f"**Current Score:** {st.session_state.score} / {total_cards}")