Update app.py
Browse files
app.py
CHANGED
@@ -29,7 +29,7 @@ def delete_asset(path):
|
|
29 |
st.error(f"Error deleting file: {e}")
|
30 |
st.rerun()
|
31 |
|
32 |
-
# ---
|
33 |
def generate_combined_pdf(selected_asset_paths):
|
34 |
"""Generates a single PDF from selected markdown and image file paths."""
|
35 |
buf = io.BytesIO()
|
@@ -76,7 +76,7 @@ def generate_combined_pdf(selected_asset_paths):
|
|
76 |
c.setFont(font_family, font_size)
|
77 |
|
78 |
# Estimate line height and character width for text wrapping
|
79 |
-
# ReportLab
|
80 |
# A common approximation for average character width is font_size * 0.6
|
81 |
avg_char_width_points = font_size * 0.6
|
82 |
# wrap_width is the number of characters that fit in one line of a column
|
@@ -176,6 +176,7 @@ def generate_combined_pdf(selected_asset_paths):
|
|
176 |
c.showPage() # Start a new page for this image
|
177 |
|
178 |
# Draw the image onto the current page
|
|
|
179 |
c.drawImage(path, pos_x, pos_y, width=draw_w, height=draw_h, preserveAspectRatio=True)
|
180 |
|
181 |
except Exception as e:
|
@@ -190,7 +191,7 @@ def generate_combined_pdf(selected_asset_paths):
|
|
190 |
c.save() # Finalize the PDF
|
191 |
buf.seek(0) # Rewind the buffer to the beginning
|
192 |
return buf.getvalue() # Return the PDF bytes
|
193 |
-
# --- End of
|
194 |
|
195 |
|
196 |
# Tabs setup
|
@@ -371,15 +372,17 @@ with tab1:
|
|
371 |
|
372 |
st.markdown("---")
|
373 |
st.subheader("📂 Available Assets")
|
374 |
-
st.markdown("Select assets below
|
375 |
|
376 |
# Get all files and filter out unwanted ones
|
377 |
all_assets = glob.glob("*.*")
|
|
|
378 |
excluded_extensions = ['.py', '.ttf']
|
379 |
-
excluded_files = ['README.md', 'index.html']
|
380 |
|
381 |
assets = sorted([
|
382 |
a for a in all_assets
|
|
|
383 |
if not (a.lower().endswith(tuple(excluded_extensions)) or os.path.basename(a) in excluded_files)
|
384 |
])
|
385 |
|
@@ -430,24 +433,29 @@ with tab1:
|
|
430 |
# Audio player takes up too much space here, just offer download
|
431 |
with open(a, 'rb') as mp3:
|
432 |
cols[2].download_button("📥", data=mp3, file_name=a, mime="audio/mpeg", key=f"download_{a}")
|
433 |
-
#
|
434 |
-
elif ext in ['
|
435 |
-
|
|
|
|
|
|
|
436 |
with open(a, 'rb') as img_file:
|
437 |
cols[2].download_button("⬇️", data=img_file.read(), file_name=a, mime=f"image/{ext}", key=f"download_{a}")
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
# Handle other file types - maybe just offer download
|
443 |
else:
|
444 |
with open(a, 'rb') as other_file:
|
445 |
cols[2].download_button("⬇️", data=other_file.read(), file_name=a, key=f"download_{a}") # Mime type is guessed by streamlit
|
446 |
|
|
|
447 |
# Delete button in the fourth column
|
448 |
cols[3].button("🗑️", key=f"del_{a}", on_click=delete_asset, args=(a,))
|
449 |
except Exception as e:
|
450 |
-
|
|
|
451 |
|
452 |
|
453 |
# --- Combined PDF Generation Button ---
|
@@ -477,11 +485,62 @@ with tab1:
|
|
477 |
)
|
478 |
st.success("Combined PDF generated!")
|
479 |
else:
|
480 |
-
|
|
|
481 |
|
482 |
except Exception as e:
|
483 |
st.error(f"An unexpected error occurred during PDF generation: {e}")
|
484 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
485 |
|
486 |
with tab2:
|
487 |
st.header("🧪 Python Code Executor & Demo")
|
|
|
29 |
st.error(f"Error deleting file: {e}")
|
30 |
st.rerun()
|
31 |
|
32 |
+
# --- Function to Generate Combined PDF ---
|
33 |
def generate_combined_pdf(selected_asset_paths):
|
34 |
"""Generates a single PDF from selected markdown and image file paths."""
|
35 |
buf = io.BytesIO()
|
|
|
76 |
c.setFont(font_family, font_size)
|
77 |
|
78 |
# Estimate line height and character width for text wrapping
|
79 |
+
# ReportLab measures in points. Approximating char width for wrapping.
|
80 |
# A common approximation for average character width is font_size * 0.6
|
81 |
avg_char_width_points = font_size * 0.6
|
82 |
# wrap_width is the number of characters that fit in one line of a column
|
|
|
176 |
c.showPage() # Start a new page for this image
|
177 |
|
178 |
# Draw the image onto the current page
|
179 |
+
# Use the path directly with c.drawImage for files on disk
|
180 |
c.drawImage(path, pos_x, pos_y, width=draw_w, height=draw_h, preserveAspectRatio=True)
|
181 |
|
182 |
except Exception as e:
|
|
|
191 |
c.save() # Finalize the PDF
|
192 |
buf.seek(0) # Rewind the buffer to the beginning
|
193 |
return buf.getvalue() # Return the PDF bytes
|
194 |
+
# --- End of Combined PDF Function ---
|
195 |
|
196 |
|
197 |
# Tabs setup
|
|
|
372 |
|
373 |
st.markdown("---")
|
374 |
st.subheader("📂 Available Assets")
|
375 |
+
st.markdown("Select assets below to include in a combined PDF.")
|
376 |
|
377 |
# Get all files and filter out unwanted ones
|
378 |
all_assets = glob.glob("*.*")
|
379 |
+
# Removed '.txt' from excluded extensions
|
380 |
excluded_extensions = ['.py', '.ttf']
|
381 |
+
excluded_files = ['README.md', 'index.html']
|
382 |
|
383 |
assets = sorted([
|
384 |
a for a in all_assets
|
385 |
+
# Check if extension is in excluded list OR if the full name is in excluded files
|
386 |
if not (a.lower().endswith(tuple(excluded_extensions)) or os.path.basename(a) in excluded_files)
|
387 |
])
|
388 |
|
|
|
433 |
# Audio player takes up too much space here, just offer download
|
434 |
with open(a, 'rb') as mp3:
|
435 |
cols[2].download_button("📥", data=mp3, file_name=a, mime="audio/mpeg", key=f"download_{a}")
|
436 |
+
# Offer download for common text files like txt, csv etc.
|
437 |
+
elif ext in ['md', 'txt', 'csv', 'json', 'xml', 'log']:
|
438 |
+
with open(a, 'r', encoding='utf-8') as text_file:
|
439 |
+
cols[2].download_button("⬇️", data=text_file.read(), file_name=a, mime="text/plain", key=f"download_{a}")
|
440 |
+
# Offer download for common image files
|
441 |
+
elif ext in ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff']:
|
442 |
with open(a, 'rb') as img_file:
|
443 |
cols[2].download_button("⬇️", data=img_file.read(), file_name=a, mime=f"image/{ext}", key=f"download_{a}")
|
444 |
+
# Offer download for common video files (Streamlit doesn't have easy preview here)
|
445 |
+
elif ext in ['mp4', 'webm', 'ogg', 'avi', 'mov']:
|
446 |
+
with open(a, 'rb') as video_file:
|
447 |
+
cols[2].download_button("⬇️", data=video_file.read(), file_name=a, mime=f"video/{ext}", key=f"download_{a}")
|
448 |
+
# Handle other file types - maybe just offer download with guessed mime
|
449 |
else:
|
450 |
with open(a, 'rb') as other_file:
|
451 |
cols[2].download_button("⬇️", data=other_file.read(), file_name=a, key=f"download_{a}") # Mime type is guessed by streamlit
|
452 |
|
453 |
+
|
454 |
# Delete button in the fourth column
|
455 |
cols[3].button("🗑️", key=f"del_{a}", on_click=delete_asset, args=(a,))
|
456 |
except Exception as e:
|
457 |
+
# Display error next to the file if handling fails
|
458 |
+
cols[3].error(f"Error: {e}")
|
459 |
|
460 |
|
461 |
# --- Combined PDF Generation Button ---
|
|
|
485 |
)
|
486 |
st.success("Combined PDF generated!")
|
487 |
else:
|
488 |
+
# This case might happen if selected files couldn't be read/processed
|
489 |
+
st.warning("Generated PDF is empty. Check selected files or console for errors.")
|
490 |
|
491 |
except Exception as e:
|
492 |
st.error(f"An unexpected error occurred during PDF generation: {e}")
|
493 |
|
494 |
+
# --- Image Gallery ---
|
495 |
+
st.markdown("---")
|
496 |
+
st.subheader("🖼️ Image Gallery")
|
497 |
+
# Find common image file types
|
498 |
+
image_files = sorted(glob.glob("*.png") + glob.glob("*.jpg") + glob.glob("*.jpeg") + glob.glob("*.gif") + glob.glob("*.bmp") + glob.glob("*.tiff"))
|
499 |
+
|
500 |
+
if not image_files:
|
501 |
+
st.info("No image files found in the directory.")
|
502 |
+
else:
|
503 |
+
# Slider to control the number of columns in the gallery
|
504 |
+
image_cols = st.slider("Image Gallery Columns", min_value=1, max_value=10, value=5)
|
505 |
+
# Ensure image_cols is at least 1
|
506 |
+
image_cols = max(1, image_cols)
|
507 |
+
|
508 |
+
# Display images in columns
|
509 |
+
cols = st.columns(image_cols)
|
510 |
+
for idx, image_file in enumerate(image_files):
|
511 |
+
with cols[idx % image_cols]: # Cycle through columns
|
512 |
+
try:
|
513 |
+
img = Image.open(image_file)
|
514 |
+
st.image(img, caption=os.path.basename(image_file), use_container_width=True)
|
515 |
+
except Exception as e:
|
516 |
+
st.warning(f"Could not display image {image_file}: {e}")
|
517 |
+
|
518 |
+
|
519 |
+
# --- Video Gallery ---
|
520 |
+
st.markdown("---")
|
521 |
+
st.subheader("🎥 Video Gallery")
|
522 |
+
# Find common video file types
|
523 |
+
video_files = sorted(glob.glob("*.mp4") + glob.glob("*.webm") + glob.glob("*.ogg") + glob.glob("*.avi") + glob.glob("*.mov"))
|
524 |
+
|
525 |
+
if not video_files:
|
526 |
+
st.info("No video files found in the directory.")
|
527 |
+
else:
|
528 |
+
# Slider to control the number of columns in the gallery
|
529 |
+
video_cols = st.slider("Video Gallery Columns", min_value=1, max_value=5, value=3)
|
530 |
+
# Ensure video_cols is at least 1
|
531 |
+
video_cols = max(1, video_cols)
|
532 |
+
|
533 |
+
|
534 |
+
# Display videos in columns
|
535 |
+
cols = st.columns(video_cols)
|
536 |
+
for idx, video_file in enumerate(video_files):
|
537 |
+
with cols[idx % video_cols]: # Cycle through columns
|
538 |
+
try:
|
539 |
+
# Streamlit's built-in video player is simpler than custom HTML
|
540 |
+
st.video(video_file, caption=os.path.basename(video_file))
|
541 |
+
except Exception as e:
|
542 |
+
st.warning(f"Could not display video {video_file}: {e}")
|
543 |
+
|
544 |
|
545 |
with tab2:
|
546 |
st.header("🧪 Python Code Executor & Demo")
|