arpit13 commited on
Commit
b2b1442
·
verified ·
1 Parent(s): 4f7925a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +466 -0
app.py CHANGED
@@ -0,0 +1,466 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import time
4
+ import tempfile
5
+ import subprocess
6
+ import re
7
+ import PyPDF2
8
+ import docx
9
+ from fpdf import FPDF
10
+ from pathlib import Path
11
+ import threading
12
+ import queue
13
+ import logging
14
+ from datetime import datetime
15
+ import io
16
+
17
+ # Set up logging
18
+ logging.basicConfig(
19
+ level=logging.INFO,
20
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
21
+ handlers=[
22
+ logging.FileHandler("streamlit_app.log"),
23
+ logging.StreamHandler()
24
+ ]
25
+ )
26
+ logger = logging.getLogger(__name__)
27
+
28
+ # Set page configuration
29
+ st.set_page_config(
30
+ page_title="B.Tech Assignment Solution Generator",
31
+ page_icon="🎓",
32
+ layout="wide",
33
+ initial_sidebar_state="expanded",
34
+ menu_items={
35
+ 'About': "# B.Tech Assignment Solution Generator\nThis app processes B.Tech assignments and generates comprehensive solutions."
36
+ }
37
+ )
38
+
39
+ # Apply dark theme
40
+ st.markdown("""
41
+ <style>
42
+ .main {
43
+ background-color: #0E1117;
44
+ color: white;
45
+ }
46
+ .stButton>button {
47
+ background-color: #4CAF50;
48
+ color: white;
49
+ border-radius: 8px;
50
+ padding: 10px 24px;
51
+ font-weight: bold;
52
+ border: none;
53
+ transition-duration: 0.4s;
54
+ }
55
+ .stButton>button:hover {
56
+ background-color: #45a049;
57
+ }
58
+ .stTextInput>div>div>input {
59
+ background-color: #1E2126;
60
+ color: white;
61
+ }
62
+ .stMarkdown {
63
+ color: white;
64
+ }
65
+ .css-1cpxqw2 {
66
+ background-color: #262730;
67
+ border-radius: 10px;
68
+ padding: 20px;
69
+ margin-bottom: 20px;
70
+ }
71
+ .css-1v3fvcr {
72
+ background-color: #0E1117;
73
+ }
74
+ .css-18e3th9 {
75
+ padding-top: 2rem;
76
+ }
77
+ .css-1kyxreq {
78
+ justify-content: center;
79
+ align-items: center;
80
+ }
81
+ .stProgress > div > div > div > div {
82
+ background-color: #4CAF50;
83
+ }
84
+ .log-container {
85
+ background-color: #1E2126;
86
+ color: #B0B0B0;
87
+ padding: 15px;
88
+ border-radius: 8px;
89
+ height: 300px;
90
+ overflow-y: auto;
91
+ font-family: monospace;
92
+ margin-bottom: 20px;
93
+ }
94
+ .success-message {
95
+ color: #4CAF50;
96
+ font-weight: bold;
97
+ }
98
+ .error-message {
99
+ color: #FF5252;
100
+ font-weight: bold;
101
+ }
102
+ .info-message {
103
+ color: #2196F3;
104
+ }
105
+ .warning-message {
106
+ color: #FFC107;
107
+ }
108
+ .pdf-container {
109
+ background-color: #262730;
110
+ padding: 20px;
111
+ border-radius: 10px;
112
+ margin-top: 20px;
113
+ }
114
+ .download-button {
115
+ background-color: #2196F3;
116
+ color: white;
117
+ padding: 10px 15px;
118
+ border-radius: 5px;
119
+ text-decoration: none;
120
+ display: inline-block;
121
+ margin-top: 10px;
122
+ }
123
+ </style>
124
+ """, unsafe_allow_html=True)
125
+
126
+ def extract_text_from_pdf(file):
127
+ """Extract text from a PDF file."""
128
+ try:
129
+ pdf_reader = PyPDF2.PdfReader(file)
130
+ text = ""
131
+ for page in pdf_reader.pages:
132
+ text += page.extract_text() + "\n"
133
+ return text
134
+ except Exception as e:
135
+ logger.error(f"Error extracting text from PDF: {e}")
136
+ st.error(f"Error extracting text from PDF: {e}")
137
+ return None
138
+
139
+ def extract_text_from_docx(file):
140
+ """Extract text from a DOCX file."""
141
+ try:
142
+ doc = docx.Document(file)
143
+ text = ""
144
+ for para in doc.paragraphs:
145
+ text += para.text + "\n"
146
+ return text
147
+ except Exception as e:
148
+ logger.error(f"Error extracting text from DOCX: {e}")
149
+ st.error(f"Error extracting text from DOCX: {e}")
150
+ return None
151
+
152
+ def create_pdf(content, filename="solution.pdf"):
153
+ """Create a PDF file from the solution content."""
154
+ try:
155
+ pdf = FPDF()
156
+ pdf.add_page()
157
+ pdf.set_auto_page_break(auto=True, margin=15)
158
+
159
+ # Set font for title
160
+ pdf.set_font("Arial", "B", 16)
161
+ pdf.cell(0, 10, "B.Tech Assignment Solution", ln=True, align="C")
162
+ pdf.ln(5)
163
+
164
+ # Set font for content
165
+ pdf.set_font("Arial", "", 12)
166
+
167
+ # Process content by paragraphs
168
+ paragraphs = content.split('\n')
169
+ for para in paragraphs:
170
+ # Check if this is a heading (simple heuristic)
171
+ if para.strip() and len(para.strip()) < 100 and para.strip().isupper():
172
+ pdf.set_font("Arial", "B", 14)
173
+ pdf.cell(0, 10, para, ln=True)
174
+ pdf.set_font("Arial", "", 12)
175
+ else:
176
+ # Handle regular paragraph
177
+ pdf.multi_cell(0, 10, para)
178
+ pdf.ln(2)
179
+
180
+ # Save PDF to a bytes buffer
181
+ pdf_buffer = io.BytesIO()
182
+ pdf.output(pdf_buffer)
183
+ pdf_buffer.seek(0)
184
+
185
+ return pdf_buffer
186
+ except Exception as e:
187
+ logger.error(f"Error creating PDF: {e}")
188
+ st.error(f"Error creating PDF: {e}")
189
+ return None
190
+
191
+ def process_log_line(line):
192
+ """Process a log line to determine its type and format it for display."""
193
+ line = line.strip()
194
+ if not line:
195
+ return None, None
196
+
197
+ # Determine message type
198
+ if "ERROR" in line or "error" in line.lower():
199
+ msg_type = "error"
200
+ elif "WARNING" in line or "warning" in line.lower():
201
+ msg_type = "warning"
202
+ elif "INFO" in line or "info" in line.lower():
203
+ msg_type = "info"
204
+ else:
205
+ msg_type = "info"
206
+
207
+ # Extract the important part of the message
208
+ # Remove timestamp and log level if present
209
+ match = re.search(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - \w+ - \w+ - (.*)', line)
210
+ if match:
211
+ message = match.group(1)
212
+ else:
213
+ message = line
214
+
215
+ return msg_type, message
216
+
217
+ def monitor_log_file(log_file, message_queue, stop_event):
218
+ """Monitor the log file for new content and put it in the queue."""
219
+ try:
220
+ with open(log_file, 'r') as f:
221
+ # Move to the end of the file
222
+ f.seek(0, 2)
223
+
224
+ while not stop_event.is_set():
225
+ line = f.readline()
226
+ if line:
227
+ msg_type, message = process_log_line(line)
228
+ if msg_type and message:
229
+ message_queue.put((msg_type, message))
230
+ else:
231
+ # No new line, wait a bit
232
+ time.sleep(0.1)
233
+ except Exception as e:
234
+ logger.error(f"Error monitoring log file: {e}")
235
+ message_queue.put(("error", f"Error monitoring log file: {e}"))
236
+
237
+ def run_assignment_processor(input_file_path, message_queue):
238
+ """Run the assignment processor and capture its output."""
239
+ try:
240
+ # Get the directory of the current script
241
+ script_dir = os.path.dirname(os.path.abspath(__file__))
242
+
243
+ # Construct the path to streamlit_main.py
244
+ main_script = os.path.join(script_dir, "streamlit_main.py")
245
+
246
+ # Activate virtual environment if available
247
+ venv_python = os.path.join(script_dir, "venv", "bin", "python")
248
+ if os.path.exists(venv_python):
249
+ python_cmd = venv_python
250
+ else:
251
+ python_cmd = "python3"
252
+
253
+ # Run the assignment processor
254
+ cmd = [python_cmd, main_script, input_file_path]
255
+
256
+ # Add log message
257
+ message_queue.put(("info", "Starting assignment processing..."))
258
+
259
+ # Execute the command
260
+ process = subprocess.Popen(
261
+ cmd,
262
+ stdout=subprocess.PIPE,
263
+ stderr=subprocess.PIPE,
264
+ text=True
265
+ )
266
+
267
+ # Capture and process output
268
+ for line in process.stdout:
269
+ msg_type, message = process_log_line(line)
270
+ if msg_type and message:
271
+ message_queue.put((msg_type, message))
272
+
273
+ # Wait for process to complete
274
+ return_code = process.wait()
275
+
276
+ if return_code != 0:
277
+ # Capture error output if process failed
278
+ error_output = process.stderr.read()
279
+ message_queue.put(("error", f"Process failed with return code {return_code}: {error_output}"))
280
+ return False
281
+
282
+ # Add completion message
283
+ message_queue.put(("success", "COMPLETED B.TECH ASSIGNMENT SOLUTION PIPELINE"))
284
+ return True
285
+ except Exception as e:
286
+ logger.error(f"Error running assignment processor: {e}")
287
+ message_queue.put(("error", f"Error running assignment processor: {e}"))
288
+ return False
289
+
290
+ def main():
291
+ # Header
292
+ st.title("B.Tech Assignment Solution Generator")
293
+ st.markdown("Upload your assignment file (PDF or DOCX) and get comprehensive solutions.")
294
+
295
+ # File uploader
296
+ uploaded_file = st.file_uploader("Choose an assignment file", type=["pdf", "docx"])
297
+
298
+ if uploaded_file is not None:
299
+ st.success(f"File uploaded: {uploaded_file.name}")
300
+
301
+ # Extract text from the uploaded file
302
+ if uploaded_file.name.endswith('.pdf'):
303
+ text = extract_text_from_pdf(uploaded_file)
304
+ elif uploaded_file.name.endswith('.docx'):
305
+ text = extract_text_from_docx(uploaded_file)
306
+ else:
307
+ st.error("Unsupported file format. Please upload a PDF or DOCX file.")
308
+ return
309
+
310
+ if text is None:
311
+ st.error("Failed to extract text from the file.")
312
+ return
313
+
314
+ # Preview the extracted text
315
+ with st.expander("Preview Extracted Text", expanded=False):
316
+ st.text_area("Extracted Text", text, height=200)
317
+
318
+ # Process button
319
+ if st.button("Generate Solution"):
320
+ # Create a temporary file to save the extracted text
321
+ with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as temp_file:
322
+ temp_file.write(text)
323
+ temp_file_path = temp_file.name
324
+
325
+ try:
326
+ # Set up progress tracking
327
+ progress_bar = st.progress(0)
328
+ status_text = st.empty()
329
+
330
+ # Create a container for log messages
331
+ st.subheader("Processing Status")
332
+ log_container = st.empty()
333
+ log_messages = []
334
+
335
+ # Create a queue for messages
336
+ message_queue = queue.Queue()
337
+
338
+ # Create an event to signal thread to stop
339
+ stop_event = threading.Event()
340
+
341
+ # Start a thread to monitor the log file
342
+ log_file = "btech_solution_system.log"
343
+ log_thread = threading.Thread(
344
+ target=monitor_log_file,
345
+ args=(log_file, message_queue, stop_event)
346
+ )
347
+ log_thread.daemon = True
348
+ log_thread.start()
349
+
350
+ # Start processing in a separate thread
351
+ processing_thread = threading.Thread(
352
+ target=run_assignment_processor,
353
+ args=(temp_file_path, message_queue)
354
+ )
355
+ processing_thread.daemon = True
356
+ processing_thread.start()
357
+
358
+ # Update progress and display log messages
359
+ start_time = time.time()
360
+ solution_content = None
361
+
362
+ # Define key stages and their progress values
363
+ stages = {
364
+ "ANALYZING QUESTIONS": 10,
365
+ "RESEARCHING INFORMATION": 30,
366
+ "DEVELOPING INITIAL SOLUTIONS": 50,
367
+ "VERIFYING SOLUTIONS": 70,
368
+ "REVISING SOLUTIONS": 85,
369
+ "FORMATTING FINAL REPORT": 95,
370
+ "COMPLETED": 100
371
+ }
372
+
373
+ current_progress = 0
374
+
375
+ # Update status until processing is complete
376
+ while processing_thread.is_alive() or not message_queue.empty():
377
+ # Check for new messages
378
+ try:
379
+ while not message_queue.empty():
380
+ msg_type, message = message_queue.get(block=False)
381
+
382
+ # Update progress based on message content
383
+ for stage, progress_value in stages.items():
384
+ if stage in message:
385
+ current_progress = progress_value
386
+ break
387
+
388
+ # Format message based on type
389
+ formatted_msg = f"<div class='{msg_type}-message'>{message}</div>"
390
+ log_messages.append(formatted_msg)
391
+
392
+ # Keep only the last 20 messages to avoid cluttering
393
+ if len(log_messages) > 20:
394
+ log_messages = log_messages[-20:]
395
+
396
+ # Update log display
397
+ log_container.markdown(
398
+ f"<div class='log-container'>{''.join(log_messages)}</div>",
399
+ unsafe_allow_html=True
400
+ )
401
+
402
+ # Check if solution is ready
403
+ if "COMPLETED B.TECH ASSIGNMENT SOLUTION PIPELINE" in message:
404
+ # Try to read the solution file
405
+ try:
406
+ solution_file = "solution.txt"
407
+ if os.path.exists(solution_file):
408
+ with open(solution_file, 'r') as f:
409
+ solution_content = f.read()
410
+ except Exception as e:
411
+ logger.error(f"Error reading solution file: {e}")
412
+ log_messages.append(f"<div class='error-message'>Error reading solution file: {e}</div>")
413
+ except queue.Empty:
414
+ pass
415
+
416
+ # Update progress bar
417
+ progress_bar.progress(current_progress)
418
+ status_text.text(f"Processing... ({current_progress}%)")
419
+
420
+ # Check if processing is complete
421
+ if current_progress >= 100:
422
+ break
423
+
424
+ # Check timeout (30 minutes)
425
+ if time.time() - start_time > 1800:
426
+ status_text.error("Processing timed out after 30 minutes.")
427
+ break
428
+
429
+ time.sleep(0.5)
430
+
431
+ # Stop the log monitoring thread
432
+ stop_event.set()
433
+
434
+ # Check if solution was found
435
+ if solution_content:
436
+ # Update progress to 100%
437
+ progress_bar.progress(100)
438
+ status_text.success("Solution generated successfully!")
439
+
440
+ # Display the solution
441
+ st.subheader("Generated Solution")
442
+ st.markdown(solution_content)
443
+
444
+ # Create PDF
445
+ pdf_buffer = create_pdf(solution_content)
446
+
447
+ if pdf_buffer:
448
+ # Provide download button for PDF
449
+ st.download_button(
450
+ label="Download Solution as PDF",
451
+ data=pdf_buffer,
452
+ file_name="btech_assignment_solution.pdf",
453
+ mime="application/pdf",
454
+ key="solution-pdf",
455
+ help="Click to download the solution as a PDF file"
456
+ )
457
+ else:
458
+ status_text.error("Failed to generate solution.")
459
+
460
+ finally:
461
+ # Clean up temporary file
462
+ if os.path.exists(temp_file_path):
463
+ os.unlink(temp_file_path)
464
+
465
+ if __name__ == "__main__":
466
+ main()