Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import zipfile | |
| import io | |
| import os | |
| import logging | |
| from dotenv import load_dotenv | |
| from meta_data import meta_data_helper_function | |
| # Load environment variables from .env file | |
| load_dotenv() | |
| # Set up logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Set page config to full screen | |
| st.set_page_config( | |
| page_title="EXIF Metadata Adder", | |
| page_icon="π·", | |
| layout="wide" | |
| ) | |
| def check_token(user_token): | |
| ACCESS_TOKEN = os.getenv("ACCESS_TOKEN") | |
| if not ACCESS_TOKEN: | |
| logger.critical("ACCESS_TOKEN not set in environment.") | |
| return False, "Server error: Access token not configured." | |
| if user_token == ACCESS_TOKEN: | |
| logger.info("Access token validated successfully.") | |
| return True, "" | |
| logger.warning("Invalid access token attempt.") | |
| return False, "Invalid token." | |
| def is_image_file(filename): | |
| """Check if file is a supported image format.""" | |
| return filename.lower().endswith(('.jpeg', '.jpg', '.png', '.webp')) | |
| def process_single_image(image_bytes): | |
| """Process a single image and add EXIF metadata.""" | |
| try: | |
| return meta_data_helper_function(image_bytes) | |
| except Exception as e: | |
| st.error(f"Error processing image: {str(e)}") | |
| return None | |
| def extract_images_from_zip(zip_file): | |
| """Extract image files from uploaded ZIP.""" | |
| images = {} | |
| try: | |
| with zipfile.ZipFile(zip_file, 'r') as zip_ref: | |
| for file_info in zip_ref.filelist: | |
| if not file_info.is_dir() and is_image_file(file_info.filename): | |
| # Read the image data | |
| image_data = zip_ref.read(file_info.filename) | |
| # Use just the filename, not the full path | |
| clean_filename = os.path.basename(file_info.filename) | |
| images[clean_filename] = image_data | |
| except Exception as e: | |
| st.error(f"Error extracting ZIP file: {str(e)}") | |
| return images | |
| def create_download_zip(processed_images): | |
| """Create a ZIP file containing all processed images.""" | |
| zip_buffer = io.BytesIO() | |
| with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: | |
| for filename, image_data in processed_images.items(): | |
| # Ensure filename has .jpg extension | |
| if not filename.lower().endswith('.jpg'): | |
| name, _ = os.path.splitext(filename) | |
| filename = f"{name}.jpg" | |
| zip_file.writestr(filename, image_data) | |
| zip_buffer.seek(0) | |
| return zip_buffer.getvalue() | |
| def main(): | |
| st.title("π· EXIF Metadata Adder") | |
| st.write("Upload images or ZIP files to add realistic synthetic EXIF metadata") | |
| # Authentication section | |
| if 'authenticated' not in st.session_state: | |
| st.session_state.authenticated = False | |
| if not st.session_state.authenticated: | |
| st.header("π Authentication Required") | |
| st.write("Please enter your access token to continue:") | |
| token_input = st.text_input( | |
| "Access Token", | |
| type="password", | |
| help="Enter your access token to access the EXIF metadata tools" | |
| ) | |
| col1, col2 = st.columns([1, 3]) | |
| with col1: | |
| if st.button("π Login", type="primary"): | |
| if token_input: | |
| is_valid, error_msg = check_token(token_input) | |
| if is_valid: | |
| st.session_state.authenticated = True | |
| st.success("β Authentication successful!") | |
| st.rerun() | |
| else: | |
| st.error(f"β {error_msg}") | |
| else: | |
| st.warning("β οΈ Please enter an access token") | |
| return | |
| # Show logout option in sidebar when authenticated | |
| if st.session_state.authenticated: | |
| if st.button("π Logout"): | |
| st.session_state.authenticated = False | |
| st.rerun() | |
| # Main app functionality (only shown when authenticated) | |
| # File uploader | |
| uploaded_files = st.file_uploader( | |
| "Choose images or ZIP files", | |
| type=['jpeg', 'jpg', 'png', 'webp', 'zip'], | |
| accept_multiple_files=True, | |
| help="Supported formats: JPEG, JPG, PNG, WEBP, ZIP" | |
| ) | |
| if uploaded_files: | |
| # Separate images and ZIP files | |
| image_files = [] | |
| zip_files = [] | |
| for file in uploaded_files: | |
| if file.name.lower().endswith('.zip'): | |
| zip_files.append(file) | |
| elif is_image_file(file.name): | |
| image_files.append(file) | |
| # Process files | |
| all_images_to_process = {} | |
| # Add individual image files | |
| for img_file in image_files: | |
| all_images_to_process[img_file.name] = img_file.read() | |
| # Extract images from ZIP files | |
| for zip_file in zip_files: | |
| st.info(f"π¦ Extracting images from {zip_file.name}...") | |
| extracted_images = extract_images_from_zip(zip_file) | |
| all_images_to_process.update(extracted_images) | |
| if all_images_to_process: | |
| st.success(f"β Found {len(all_images_to_process)} image(s) to process") | |
| # Show file list | |
| with st.expander("π Files to Process"): | |
| for filename in all_images_to_process.keys(): | |
| st.write(f"β’ {filename}") | |
| # Process button | |
| if st.button("π Add EXIF Metadata", type="primary"): | |
| progress_bar = st.progress(0) | |
| status_text = st.empty() | |
| processed_images = {} | |
| total_files = len(all_images_to_process) | |
| for i, (filename, image_data) in enumerate(all_images_to_process.items()): | |
| status_text.text(f"Processing {filename}...") | |
| # Process the image | |
| processed_data = process_single_image(image_data) | |
| if processed_data: | |
| # Ensure output filename has .jpg extension | |
| name, _ = os.path.splitext(filename) | |
| output_filename = f"{name}.jpg" | |
| processed_images[output_filename] = processed_data | |
| # Update progress | |
| progress_bar.progress((i + 1) / total_files) | |
| status_text.text("β Processing complete!") | |
| if processed_images: | |
| st.success(f"π Successfully processed {len(processed_images)} image(s)") | |
| # Download options | |
| if len(processed_images) == 1: | |
| # Single image download | |
| filename, image_data = next(iter(processed_images.items())) | |
| st.download_button( | |
| label=f"π₯ Download {filename}", | |
| data=image_data, | |
| file_name=filename, | |
| mime="image/jpeg", | |
| type="primary" | |
| ) | |
| else: | |
| # Multiple images - create ZIP | |
| zip_data = create_download_zip(processed_images) | |
| st.download_button( | |
| label=f"π₯ Download All Images ({len(processed_images)} files)", | |
| data=zip_data, | |
| file_name="processed_images_with_exif.zip", | |
| mime="application/zip", | |
| type="primary" | |
| ) | |
| else: | |
| st.error("β No images could be processed successfully") | |
| else: | |
| st.warning("β οΈ No valid image files found in uploaded files") | |
| if __name__ == "__main__": | |
| main() | |