AruniAnkur commited on
Commit
0a4e1a5
·
verified ·
1 Parent(s): 699f7b6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +191 -306
app.py CHANGED
@@ -1,30 +1,16 @@
 
1
  import streamlit as st
2
- import requests
3
- import json
4
- import fitz # PyMuPDF
5
- from fpdf import FPDF
6
  import os
7
- import tempfile
8
- import base64
9
- import dotenv
10
  from dotenv import load_dotenv
11
  import torch
12
  from transformers import DistilBertForSequenceClassification, DistilBertTokenizer
13
  from torch.nn.functional import softmax
14
  from doctr.models import ocr_predictor
15
  from doctr.io import DocumentFile
16
- import tempfile
 
17
 
18
 
19
- def save_uploaded_file(uploaded_file):
20
- if uploaded_file is not None:
21
- file_extension = uploaded_file.name.split('.')[-1].lower()
22
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix = f'.{file_extension}')
23
- temp_file.write(uploaded_file.getvalue())
24
- temp_file.close()
25
- return temp_file.name
26
- return None
27
-
28
  load_dotenv()
29
 
30
  model = DistilBertForSequenceClassification.from_pretrained('./fine_tuned_distilbert')
@@ -35,206 +21,164 @@ mapping = {"Remembering": 0, "Understanding": 1, "Applying": 2, "Analyzing": 3,
35
  reverse_mapping = {v: k for k, v in mapping.items()}
36
  modelocr = ocr_predictor(det_arch='db_resnet50', reco_arch='crnn_vgg16_bn', pretrained=True)
37
 
38
- # Previous functions from Question Generator
39
- def get_pdf_path(pdf_source=None, uploaded_file=None):
40
- try:
41
- # If a file is uploaded locally
42
- if uploaded_file is not None:
43
- # Create a temporary file to save the uploaded PDF
44
- temp_dir = tempfile.mkdtemp()
45
- pdf_path = os.path.join(temp_dir, uploaded_file.name)
46
-
47
- # Save the uploaded file
48
- with open(pdf_path, "wb") as pdf_file:
49
- pdf_file.write(uploaded_file.getvalue())
50
- return pdf_path
51
-
52
- # If a URL is provided
53
- if pdf_source:
54
- response = requests.get(pdf_source, timeout=30)
55
- response.raise_for_status()
56
-
57
- # Create a temporary file
58
- temp_dir = tempfile.mkdtemp()
59
- pdf_path = os.path.join(temp_dir, "downloaded.pdf")
60
-
61
- with open(pdf_path, "wb") as pdf_file:
62
- pdf_file.write(response.content)
63
- return pdf_path
64
-
65
- # If no source is provided
66
- st.error("No PDF source provided.")
67
- return None
68
- except Exception as e:
69
- st.error(f"Error getting PDF: {e}")
70
- return None
71
-
72
- def extract_text_pymupdf(pdf_path):
73
- try:
74
- doc = fitz.open(pdf_path)
75
- pages_content = []
76
- for page_num in range(len(doc)):
77
- page = doc[page_num]
78
- pages_content.append(page.get_text())
79
- doc.close()
80
- return " ".join(pages_content) # Join all pages into one large context string
81
- except Exception as e:
82
- st.error(f"Error extracting text from PDF: {e}")
83
- return ""
84
-
85
- def generate_ai_response(api_key, assistant_context, user_query, role_description, response_instructions, bloom_taxonomy_weights, num_questions):
86
- try:
87
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key={api_key}"
88
-
89
- prompt = f"""
90
- You are a highly knowledgeable assistant. Your task is to assist the user with the following context from an academic paper.
91
-
92
- **Role**: {role_description}
93
-
94
- **Context**: {assistant_context}
95
-
96
- **Instructions**: {response_instructions}
97
-
98
- **Bloom's Taxonomy Weights**:
99
- Knowledge: {bloom_taxonomy_weights['Knowledge']}%
100
- Comprehension: {bloom_taxonomy_weights['Comprehension']}%
101
- Application: {bloom_taxonomy_weights['Application']}%
102
- Analysis: {bloom_taxonomy_weights['Analysis']}%
103
- Synthesis: {bloom_taxonomy_weights['Synthesis']}%
104
- Evaluation: {bloom_taxonomy_weights['Evaluation']}%
105
-
106
- **Query**: {user_query}
107
-
108
- **Number of Questions**: {num_questions}
109
- """
110
-
111
- payload = {
112
- "contents": [
113
- {
114
- "parts": [
115
- {"text": prompt}
116
- ]
117
- }
118
- ]
119
- }
120
- headers = {"Content-Type": "application/json"}
121
-
122
- response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=60)
123
- response.raise_for_status()
124
-
125
- result = response.json()
126
- questions = result.get("candidates", [{}])[0].get("content", {}).get("parts", [{}])[0].get("text", "")
127
- questions_list = [question.strip() for question in questions.split("\n") if question.strip()]
128
- return questions_list
129
- except requests.RequestException as e:
130
- st.error(f"API request error: {e}")
131
- return []
132
- except Exception as e:
133
- st.error(f"Error generating questions: {e}")
134
- return []
135
-
136
- def normalize_bloom_weights(bloom_weights):
137
- total = sum(bloom_weights.values())
138
- if total != 100:
139
- normalization_factor = 100 / total
140
- # Normalize each weight by multiplying it by the normalization factor
141
- bloom_weights = {key: round(value * normalization_factor, 2) for key, value in bloom_weights.items()}
142
- return bloom_weights
143
-
144
- def generate_pdf(questions, filename="questions.pdf"):
145
- try:
146
- pdf = FPDF()
147
- pdf.set_auto_page_break(auto=True, margin=15)
148
- pdf.add_page()
149
-
150
- # Set font
151
- pdf.set_font("Arial", size=12)
152
-
153
- # Add a title or heading
154
- pdf.cell(200, 10, txt="Generated Questions", ln=True, align="C")
155
-
156
- # Add space between title and questions
157
- pdf.ln(10)
158
-
159
- # Loop through questions and add them to the PDF
160
- for i, question in enumerate(questions, 1):
161
- # Using multi_cell for wrapping the text in case it's too long
162
- pdf.multi_cell(0, 10, f"Q{i}: {question}")
163
-
164
- # Save the generated PDF to the file
165
- pdf.output(filename)
166
- return filename
167
- except Exception as e:
168
- st.error(f"Error generating PDF: {e}")
169
- return None
170
-
171
- def process_pdf_and_generate_questions(pdf_source, uploaded_file, api_key, role_description, response_instructions, bloom_taxonomy_weights, num_questions):
172
- try:
173
- # Get PDF path (either from URL or uploaded file)
174
- pdf_path = get_pdf_path(pdf_source, uploaded_file)
175
- if not pdf_path:
176
- return []
177
-
178
- # Extract text
179
- pdf_text = extract_text_pymupdf(pdf_path)
180
- if not pdf_text:
181
- return []
182
-
183
- # Generate questions
184
- assistant_context = pdf_text
185
- user_query = "Generate questions based on the above context."
186
- normalized_bloom_weights = normalize_bloom_weights(bloom_taxonomy_weights)
187
- questions = generate_ai_response(
188
- api_key,
189
- assistant_context,
190
- user_query,
191
- role_description,
192
- response_instructions,
193
- normalized_bloom_weights,
194
- num_questions
195
- )
196
-
197
- # Clean up temporary PDF file
198
- try:
199
- os.remove(pdf_path)
200
- # Remove the temporary directory
201
- os.rmdir(os.path.dirname(pdf_path))
202
- except Exception as e:
203
- st.warning(f"Could not delete temporary PDF file: {e}")
204
-
205
- return questions
206
- except Exception as e:
207
- st.error(f"Error processing PDF and generating questions: {e}")
208
- return []
209
-
210
  def main():
211
  st.set_page_config(page_title="Academic Paper Tool", page_icon="📝", layout="wide")
 
212
  # Tabs for different functionalities
213
  st.markdown("""
214
- <style>
215
- .stTabs [data-baseweb="tab"] {
216
- margin-bottom: 1rem;
217
- flex: 1;
218
- justify-content: center;
219
- }
220
- .stTabs [data-baseweb="tab-list"] button [data-testid="stMarkdownContainer"] p {
221
- font-size:2rem;
222
  padding: 0 2rem;
 
223
  margin: 0;
224
- }
225
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  """, unsafe_allow_html=True)
 
227
  tab1, tab2 = st.tabs(["Question Generator", "Paper Scorer"])
228
 
229
  if 'totalscore' not in st.session_state:
230
  st.session_state.totalscore = None
231
  if 'show_details' not in st.session_state:
232
  st.session_state.show_details = False
 
 
233
 
234
-
235
  # Question Generator Tab
236
  with tab1:
237
- st.title("🎓 Academic Paper Question Generator")
238
  st.markdown("Generate insightful questions from academic papers using Bloom's Taxonomy")
239
 
240
  # Initialize session state variables with defaults
@@ -251,11 +195,10 @@ def main():
251
 
252
  # API Configuration
253
  api_key = os.getenv('GEMINI_API_KEY')
254
- # api_key = st.sidebar.text_input("Enter Gemini API Key", type="password", value=apivalue)
255
 
256
  # Main form for PDF and question generation
257
  with st.form(key='pdf_generation_form'):
258
- st.header("PDF Source Configuration")
259
 
260
  st.session_state.pdf_url = st.text_input(
261
  "Enter the URL of the PDF",
@@ -263,7 +206,7 @@ def main():
263
  key="pdf_url_input"
264
  )
265
 
266
- st.markdown("<h3 style='text-align: center;'>OR</h3>", unsafe_allow_html=True)
267
 
268
  st.session_state.uploaded_file = st.file_uploader(
269
  "Upload a PDF file",
@@ -271,20 +214,30 @@ def main():
271
  key="pdf_file_upload"
272
  )
273
 
 
 
 
 
 
 
 
 
 
 
274
  # Bloom's Taxonomy Weights
275
  st.subheader("Adjust Bloom's Taxonomy Weights")
276
  col1, col2, col3 = st.columns(3)
277
 
278
  with col1:
279
- knowledge = st.slider("Knowledge or Remembering: Remembering information", 0, 100, 20, key='knowledge_slider')
280
- application = st.slider("Application: Use knowledge in new situations or solve problems.", 0, 100, 20, key='application_slider')
281
 
282
  with col2:
283
- comprehension = st.slider("Comprehension or Understanding: Comprehend and explain ideas or concepts.", 0, 100, 20, key='comprehension_slider')
284
  analysis = st.slider("Analysis: Breaking down a whole into component parts", 0, 100, 20, key='analysis_slider')
285
 
286
  with col3:
287
- synthesis = st.slider("Synthesis or Creating: Putting parts together to form a new and integrated whole", 0, 100, 10, key='synthesis_slider')
288
  evaluation = st.slider("Evaluation: Making and defending judgments based on internal evidence or external criteria", 0, 100, 10, key='evaluation_slider')
289
 
290
  # Collect the Bloom's Taxonomy weights
@@ -331,38 +284,48 @@ def main():
331
  role_description=role_description,
332
  response_instructions=response_instructions,
333
  bloom_taxonomy_weights=normalized_bloom_weights,
334
- num_questions=num_questions
 
 
335
  )
 
336
  if st.session_state.questions:
337
  st.header("Generated Questions")
338
 
339
  # Create a form for question management to prevent reload
340
  with st.form(key='questions_form'):
341
  for idx, question in enumerate(st.session_state.questions, 1):
342
- cols = st.columns([4, 1]) # Create two columns for radio buttons (Accept, Discard)
343
 
344
  with cols[0]:
 
345
  st.write(f"Q{idx}: {question}")
 
 
 
 
 
346
 
347
  # Use radio buttons for selection
348
  with cols[1]:
349
- # Default value is 'Discard', so users can change it to 'Accept'
350
- selected_option = st.radio(f"Select an option for Q{idx}", ["Accept", "Discard"], key=f"radio_{idx}", index=1)
 
 
 
 
351
 
352
  # Handle radio button state changes
353
  if selected_option == "Accept":
354
- # Add to accepted questions if 'Accept' is selected
355
  if question not in st.session_state.accepted_questions:
356
  st.session_state.accepted_questions.append(question)
357
  else:
358
- # Remove from accepted questions if 'Discard' is selected
359
  if question in st.session_state.accepted_questions:
360
  st.session_state.accepted_questions.remove(question)
361
 
362
  # Submit button for question selection
363
  submit_questions = st.form_submit_button("Update Accepted Questions")
364
 
365
-
366
  # Show accepted questions
367
  if st.session_state.accepted_questions:
368
  st.header("Accepted Questions")
@@ -394,12 +357,10 @@ def main():
394
  - Support for PDF via URL or local upload
395
  """)
396
  with tab2:
397
- st.title("📄 Academic Paper Scorer")
398
-
399
- # Add a descriptive subheader
400
- st.markdown("### Evaluate the Quality of Your Academic Paper")
401
-
402
- # Create a styled container for the upload section
403
  st.markdown("""
404
  <style>
405
  .upload-container {
@@ -430,7 +391,12 @@ def main():
430
  type=['pdf','jpg','png','jpeg'],
431
  label_visibility="collapsed"
432
  )
433
- # Custom submit button with some styling
 
 
 
 
 
434
  submit_button = st.form_submit_button(
435
  "Score Paper",
436
  use_container_width=True,
@@ -440,7 +406,7 @@ def main():
440
  if submit_button:
441
  # Calculate total score
442
  pdf_path = save_uploaded_file(uploaded_file)
443
- dummydata = sendtogemini(pdf_path)
444
  #print(dummydata)
445
  total_score = {'Remembering': 0, 'Understanding': 0, 'Applying': 0, 'Analyzing': 0, 'Evaluating': 0, 'Creating': 0}
446
  for item in dummydata:
@@ -483,7 +449,7 @@ def main():
483
  with col:
484
  # Determine color based on score
485
  score = round(item['score'][category],ndigits=3)
486
- color = 'green' if score > .7 else 'orange' if score > .4 else 'red'
487
 
488
  st.markdown(f"""
489
  <div style="text-align: center;
@@ -502,87 +468,6 @@ def main():
502
  if idx < len(dummydata):
503
  st.markdown('---')
504
 
505
- def predict_with_loaded_model(text):
506
- inputs = tokenizer(text, return_tensors='pt', padding=True, truncation=True, max_length=512)
507
- input_ids = inputs['input_ids'].to(device)
508
- model.eval()
509
- with torch.no_grad():
510
- outputs = model(input_ids)
511
- logits = outputs.logits
512
- probabilities = softmax(logits, dim=-1)
513
- probabilities = probabilities.squeeze().cpu().numpy()
514
- # Convert to float and format to 3 decimal places
515
- class_probabilities = {reverse_mapping[i]: float(f"{prob:.3f}") for i, prob in enumerate(probabilities)}
516
- return class_probabilities
517
-
518
- # def process_document(input_path):
519
- # return {'Avg_Confidence': 0.9397169561947093, 'String': ['What are the key differences between classification and regression tasks in', 'supervised learning, and how do you determine which algorithm to use for a', 'specific problem?', 'e How does clustering differ from dimensionality reduction, and can you', 'provide real-world examples of where each is applied?', 'What are common evaluation metrics for classification models, and how do', 'precision, recall, and F1-score relate to each other?', 'How do convolutional neural networks (CNNS) and recurrent neural networks', '(RNNS) differ in their architecture and applications?', 'What steps can be taken to identify and mitigate bias in machine learning', 'models, and why is this an important consideration?']}
520
-
521
- def process_document(input_path):
522
- if input_path.lower().endswith(".pdf"):
523
- doc = DocumentFile.from_pdf(input_path)
524
- #print(f"Number of pages: {len(doc)}")
525
- elif input_path.lower().endswith((".jpg", ".jpeg", ".png", ".bmp", ".tiff")):
526
- doc = DocumentFile.from_images(input_path)
527
- else:
528
- raise ValueError("Unsupported file type. Please provide a PDF or an image file.")
529
- result = modelocr(doc)
530
- def calculate_average_confidence(result):
531
- total_confidence = 0
532
- word_count = 0
533
- for page in result.pages:
534
- for block in page.blocks:
535
- for line in block.lines:
536
- for word in line.words:
537
- total_confidence += word.confidence
538
- word_count += 1
539
- average_confidence = total_confidence / word_count if word_count > 0 else 0
540
- return average_confidence
541
- average_confidence = calculate_average_confidence(result)
542
- string_result = result.render()
543
- return {'Avg_Confidence': average_confidence, 'String':string_result.split('\n')}
544
-
545
- def sendtogemini(inputpath):
546
- qw = process_document(inputpath)
547
- questionset = str(qw['String'])
548
- # send this prompt to gemini :
549
- questionset += """You are given a list of text fragments containing questions fragments extracted by an ocr model. Your task is to:
550
- # only Merge the question fragments into complete and coherent questions.Don't answer then.
551
- # Separate each question , start a new question with @ to make them easily distinguishable for further processing."""
552
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key={os.getenv('GEMINI_API_KEY')}"
553
-
554
- payload = {
555
- "contents": [
556
- {
557
- "parts": [
558
- {"text": questionset}
559
- ]
560
- }
561
- ]
562
- }
563
- headers = {"Content-Type": "application/json"}
564
-
565
- response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=60)
566
- result = response.json()
567
- res1 = result.get("candidates", [{}])[0].get("content", {}).get("parts", [{}])[0].get("text", "")
568
- question = []
569
- for i in res1.split('\n'):
570
- i = i.strip()
571
- if len(i) > 0:
572
- if i[0] == '@':
573
- i = i[1:].strip().lower()
574
- if i[0] == 'q':
575
- question.append(i[1:].strip())
576
- else:
577
- question.append(i)
578
- data = []
579
- for i in question:
580
- d = {}
581
- d['question'] = i
582
- d['score'] = predict_with_loaded_model(i)
583
- data.append(d)
584
- return data
585
-
586
  # Run Streamlit app
587
  if __name__ == "__main__":
588
- main()
 
1
+ from typing import Optional, Dict
2
  import streamlit as st
 
 
 
 
3
  import os
 
 
 
4
  from dotenv import load_dotenv
5
  import torch
6
  from transformers import DistilBertForSequenceClassification, DistilBertTokenizer
7
  from torch.nn.functional import softmax
8
  from doctr.models import ocr_predictor
9
  from doctr.io import DocumentFile
10
+ from functionbloom import save_uploaded_file, get_pdf_path, extract_text_pymupdf, get_bloom_taxonomy_scores,generate_ai_response,normalize_bloom_weights, generate_pdf,process_pdf_and_generate_questions,get_bloom_taxonomy_details
11
+ from functionbloom import predict_with_loaded_model, process_document, sendtogemini
12
 
13
 
 
 
 
 
 
 
 
 
 
14
  load_dotenv()
15
 
16
  model = DistilBertForSequenceClassification.from_pretrained('./fine_tuned_distilbert')
 
21
  reverse_mapping = {v: k for k, v in mapping.items()}
22
  modelocr = ocr_predictor(det_arch='db_resnet50', reco_arch='crnn_vgg16_bn', pretrained=True)
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  def main():
25
  st.set_page_config(page_title="Academic Paper Tool", page_icon="📝", layout="wide")
26
+
27
  # Tabs for different functionalities
28
  st.markdown("""
29
+ <style>
30
+ .stTabs [data-baseweb="tab"] {
31
+ margin-bottom: 1rem;
32
+ flex: 1;
33
+ justify-content: center;
34
+ }
35
+ .stTabs [data-baseweb="tab-list"] button [data-testid="stMarkdownContainer"] p {
36
+ font-size: 2rem;
37
  padding: 0 2rem;
38
+ font-weight: bold;
39
  margin: 0;
40
+ }
41
+
42
+ /* Information Button Styling */
43
+ .info-button {
44
+ background-color: #f0f2f6;
45
+ border: 1px solid #4a6cf7;
46
+ border-radius: 50%;
47
+ width: 24px;
48
+ height: 24px;
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ cursor: pointer;
53
+ margin-left: 8px;
54
+ font-weight: bold;
55
+ color: #4a6cf7;
56
+ }
57
+
58
+ /* Modal Styling */
59
+ .modal {
60
+ display: none;
61
+ position: fixed;
62
+ z-index: 1000;
63
+ left: 0;
64
+ top: 0;
65
+ width: 100%;
66
+ height: 100%;
67
+ overflow: auto;
68
+ background-color: rgba(0,0,0,0.4);
69
+ }
70
+
71
+ .modal-content {
72
+ background-color: #fefefe;
73
+ margin: 15% auto;
74
+ padding: 20px;
75
+ border: 1px solid #888;
76
+ width: 80%;
77
+ max-width: 500px;
78
+ border-radius: 10px;
79
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
80
+ }
81
+
82
+ .close-button {
83
+ color: #aaa;
84
+ float: right;
85
+ font-size: 28px;
86
+ font-weight: bold;
87
+ cursor: pointer;
88
+ }
89
+
90
+ .close-button:hover,
91
+ .close-button:focus {
92
+ color: black;
93
+ text-decoration: none;
94
+ cursor: pointer;
95
+ }
96
+
97
+ /* Question Container Styling */
98
+ .question-container {
99
+ display: flex;
100
+ align-items: start;
101
+ gap: 10px;
102
+ margin-bottom: 10px;
103
+ }
104
+
105
+ /* Info Button Styling */
106
+ .info-button {
107
+ background-color: #f0f2f6;
108
+ border: 1px solid #4a6cf7;
109
+ border-radius: 50%;
110
+ width: 24px;
111
+ height: 24px;
112
+ display: inline-flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ cursor: pointer;
116
+ font-weight: bold;
117
+ color: #4a6cf7;
118
+ flex-shrink: 0;
119
+ font-size: 14px;
120
+ }
121
+
122
+ .info-button:hover {
123
+ background-color: #4a6cf7;
124
+ color: white;
125
+ }
126
+
127
+ /* Modal Styling */
128
+ .modal {
129
+ display: none;
130
+ position: fixed;
131
+ z-index: 9999;
132
+ left: 0;
133
+ top: 0;
134
+ width: 100%;
135
+ height: 100%;
136
+ background-color: rgba(0,0,0,0.4);
137
+ }
138
+
139
+ .modal-content {
140
+ background-color: #fefefe;
141
+ margin: 15% auto;
142
+ padding: 20px;
143
+ border: 1px solid #888;
144
+ width: 80%;
145
+ max-width: 500px;
146
+ border-radius: 10px;
147
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
148
+ position: relative;
149
+ }
150
+
151
+ .close-button {
152
+ position: absolute;
153
+ right: 10px;
154
+ top: 5px;
155
+ color: #aaa;
156
+ font-size: 28px;
157
+ font-weight: bold;
158
+ cursor: pointer;
159
+ }
160
+
161
+ .close-button:hover,
162
+ .close-button:focus {
163
+ color: black;
164
+ text-decoration: none;
165
+ cursor: pointer;
166
+ }
167
+ </style>
168
  """, unsafe_allow_html=True)
169
+
170
  tab1, tab2 = st.tabs(["Question Generator", "Paper Scorer"])
171
 
172
  if 'totalscore' not in st.session_state:
173
  st.session_state.totalscore = None
174
  if 'show_details' not in st.session_state:
175
  st.session_state.show_details = False
176
+ if 'question_scores' not in st.session_state:
177
+ st.session_state.question_scores = {}
178
 
 
179
  # Question Generator Tab
180
  with tab1:
181
+ st.markdown("<h1 style='font-size: 28px;'>🎓 Academic Paper Question Generator</h1>", unsafe_allow_html=True)
182
  st.markdown("Generate insightful questions from academic papers using Bloom's Taxonomy")
183
 
184
  # Initialize session state variables with defaults
 
195
 
196
  # API Configuration
197
  api_key = os.getenv('GEMINI_API_KEY')
 
198
 
199
  # Main form for PDF and question generation
200
  with st.form(key='pdf_generation_form'):
201
+ st.subheader("PDF Source")
202
 
203
  st.session_state.pdf_url = st.text_input(
204
  "Enter the URL of the PDF",
 
206
  key="pdf_url_input"
207
  )
208
 
209
+ st.markdown("<h4 style='text-align: center;'>OR</h4>", unsafe_allow_html=True)
210
 
211
  st.session_state.uploaded_file = st.file_uploader(
212
  "Upload a PDF file",
 
214
  key="pdf_file_upload"
215
  )
216
 
217
+ # Question Length Selection
218
+ question_length = st.select_slider(
219
+ "Select Question Length",
220
+ options=["Short", "Medium", "Long"],
221
+ value="Medium",
222
+ help="Short: 10-15 words, Medium: 20-25 words, Long: 30-40 words"
223
+ )
224
+
225
+ st.session_state.include_numericals = st.checkbox("Include Numericals", key="include_numericals_checkbox")
226
+
227
  # Bloom's Taxonomy Weights
228
  st.subheader("Adjust Bloom's Taxonomy Weights")
229
  col1, col2, col3 = st.columns(3)
230
 
231
  with col1:
232
+ knowledge = st.slider("Knowledge: Remembering information", 0, 100, 20, key='knowledge_slider')
233
+ application = st.slider("Application: Using abstractions in concrete situations", 0, 100, 20, key='application_slider')
234
 
235
  with col2:
236
+ comprehension = st.slider("Comprehension: Explaining the meaning of information", 0, 100, 20, key='comprehension_slider')
237
  analysis = st.slider("Analysis: Breaking down a whole into component parts", 0, 100, 20, key='analysis_slider')
238
 
239
  with col3:
240
+ synthesis = st.slider("Synthesis: Putting parts together to form a new and integrated whole", 0, 100, 10, key='synthesis_slider')
241
  evaluation = st.slider("Evaluation: Making and defending judgments based on internal evidence or external criteria", 0, 100, 10, key='evaluation_slider')
242
 
243
  # Collect the Bloom's Taxonomy weights
 
284
  role_description=role_description,
285
  response_instructions=response_instructions,
286
  bloom_taxonomy_weights=normalized_bloom_weights,
287
+ num_questions=num_questions,
288
+ question_length=question_length,
289
+ include_numericals=st.session_state.include_numericals
290
  )
291
+
292
  if st.session_state.questions:
293
  st.header("Generated Questions")
294
 
295
  # Create a form for question management to prevent reload
296
  with st.form(key='questions_form'):
297
  for idx, question in enumerate(st.session_state.questions, 1):
298
+ cols = st.columns([4, 1]) # Create two columns
299
 
300
  with cols[0]:
301
+ # Display the question
302
  st.write(f"Q{idx}: {question}")
303
+
304
+ # Add info button using Streamlit's expander
305
+ with st.expander("Show Bloom's Taxonomy Details"):
306
+ taxonomy_details = get_bloom_taxonomy_details(st.session_state.question_scores.get(question))
307
+ st.text(taxonomy_details)
308
 
309
  # Use radio buttons for selection
310
  with cols[1]:
311
+ selected_option = st.radio(
312
+ f"Select an option for Q{idx}",
313
+ ["Accept", "Discard"],
314
+ key=f"radio_{idx}",
315
+ index=1
316
+ )
317
 
318
  # Handle radio button state changes
319
  if selected_option == "Accept":
 
320
  if question not in st.session_state.accepted_questions:
321
  st.session_state.accepted_questions.append(question)
322
  else:
 
323
  if question in st.session_state.accepted_questions:
324
  st.session_state.accepted_questions.remove(question)
325
 
326
  # Submit button for question selection
327
  submit_questions = st.form_submit_button("Update Accepted Questions")
328
 
 
329
  # Show accepted questions
330
  if st.session_state.accepted_questions:
331
  st.header("Accepted Questions")
 
357
  - Support for PDF via URL or local upload
358
  """)
359
  with tab2:
360
+ st.markdown("<h1 style='font-size: 28px;'>📄 Academic Paper Scorer</h1>", unsafe_allow_html=True)
361
+ st.markdown("Evaluate the Quality of Your Academic Paper")
362
+
363
+ # Create a styled container for the upload section
 
 
364
  st.markdown("""
365
  <style>
366
  .upload-container {
 
391
  type=['pdf','jpg','png','jpeg'],
392
  label_visibility="collapsed"
393
  )
394
+
395
+ st.markdown("<div style='text-align: center; margin-top: 20px;'><strong>OR</strong></div>", unsafe_allow_html=True)
396
+ if 'question_typed' not in st.session_state:
397
+ st.session_state.question_typed = ""
398
+ st.text_area("Paste your question here", value=st.session_state.question_typed, key="question_typed")
399
+ question_typed = st.session_state.question_typed
400
  submit_button = st.form_submit_button(
401
  "Score Paper",
402
  use_container_width=True,
 
406
  if submit_button:
407
  # Calculate total score
408
  pdf_path = save_uploaded_file(uploaded_file)
409
+ dummydata = sendtogemini(inputpath=pdf_path, question=st.session_state.question_typed)
410
  #print(dummydata)
411
  total_score = {'Remembering': 0, 'Understanding': 0, 'Applying': 0, 'Analyzing': 0, 'Evaluating': 0, 'Creating': 0}
412
  for item in dummydata:
 
449
  with col:
450
  # Determine color based on score
451
  score = round(item['score'][category],ndigits=3)
452
+ color = 'green' if score > .7 else 'orange' if score > .3 else 'red'
453
 
454
  st.markdown(f"""
455
  <div style="text-align: center;
 
468
  if idx < len(dummydata):
469
  st.markdown('---')
470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  # Run Streamlit app
472
  if __name__ == "__main__":
473
+ main()