Chat
Ask me anything
Ithy Logo
Sign in to save

Streamlit Collections App Using Python

A comprehensive implementation for managing image collections

desktop computer with code and image gallery display

Highlights

  • Collection Class Implementation: A custom Python class encapsulates collection properties and image management.
  • Dynamic GUI with Streamlit: Sidebar list supports creation, deletion, and selection of collections with immediate interface updates.
  • Grid Display and Duplicate Prevention: Images are shown in a responsive grid using container width and no duplicate filename uploads are allowed.

Overview

This application implements a fully functional Streamlit app in Python that provides users the capability to manage collections. Each collection is represented by a class that stores images, and offers methods to add or remove images while ensuring no duplicate filenames occur. The application interface comprises a sidebar that lists all collections, enabling easy navigation, creation, and deletion. Once a collection is selected, relevant information (such as the number of images, creation date, and collection name) is displayed, along with the images laid out in a responsive grid.

Application Breakdown

1. The Collection Class

The heart of the application is the Collection class. This class stores collection details like name, creation date, and images. The images are maintained in a list where duplicate file names are prevented.

Key methods:

  • add_image: Checks if the file name already exists in the collection before adding the image.
  • remove_image: Deletes the specified image from the collection.
  • get_info: A helper function to return details about the collection.

2. Collection Management

The application leverages Streamlit's session state to store and update collections dynamically without needing to reload the page. The sidebar plays an essential role by listing all collections and handling creation and deletion. With each change (addition or removal of images, collection creation or deletion), the GUI updates immediately using the appropriate rerun functionality.

3. Image Upload, Duplicate Checking & Grid Display

Users can upload multiple images to a selected collection via the file uploader widget. Before each image is added, the app checks for duplicates based on the file name. Images are then displayed in a grid format on the main area. It now uses the newer use_container_width parameter to ensure images scale appropriately with the container layout.

Sample Code Implementation

Below is a complete code example of a Python Streamlit application that implements the discussed features. This code is structured with detailed comments and separated concerns for clarity.


# Import necessary libraries
import streamlit as st
from PIL import Image
import os
from datetime import datetime
import tempfile

# Define the Collection class
class Collection:
    def __init__(self, name: str):
        self.name = name
        # Initialize an empty list to hold image file paths
        self.images = []
        self.created_at = datetime.now()

    def add_image(self, image_path: str) -> bool:
        """
        Adds an image to the collection if not already present.
        Returns True if successful, False if a duplicate is found.
        """
        filename = os.path.basename(image_path)
        # Prevent duplicates by comparing file names
        if filename not in [os.path.basename(img) for img in self.images]:
            self.images.append(image_path)
            return True
        return False

    def remove_image(self, image_path: str) -> bool:
        """
        Removes an image from the collection.
        Returns True if removed, False if image is not found.
        """
        if image_path in self.images:
            self.images.remove(image_path)
            return True
        return False

    def get_info(self) -> dict:
        """
        Returns collection details including name, creation date and image count.
        """
        return {
            "Name": self.name,
            "Created At": self.created_at.strftime("%Y-%m-%d %H:%M:%S"),
            "Number of Images": len(self.images)
        }

# Collection Manager uses Streamlit's session_state for persistence
if 'collections' not in st.session_state:
    st.session_state.collections = {}

# Create a temporary directory for saving uploaded image files
temp_dir = tempfile.mkdtemp()

def save_uploaded_file(uploaded_file):
    """
    Saves an uploaded file to a temporary directory and returns the file path.
    """
    file_path = os.path.join(temp_dir, uploaded_file.name)
    with open(file_path, "wb") as f:
        f.write(uploaded_file.getbuffer())
    return file_path

def main():
    st.title("Image Collection Manager")
    
    # Sidebar: Collection management
    st.sidebar.header("Collections")
    
    # Display list of collections in sidebar
    collections = st.session_state.collections
    collection_names = list(collections.keys())
    
    # Option to create a new collection
    new_collection_name = st.sidebar.text_input("New Collection Name")
    if st.sidebar.button("Create Collection") and new_collection_name:
        if new_collection_name not in collections:
            collections[new_collection_name] = Collection(new_collection_name)
            st.sidebar.success(f"Collection '{new_collection_name}' created successfully!")
        else:
            st.sidebar.error("A collection with that name already exists.")
    
    # Provide a selectbox to choose a collection
    if collection_names:
        selected_collection = st.sidebar.selectbox("Select a Collection", collection_names)
    else:
        selected_collection = None
    
    # Display collection details if selected
    if selected_collection and selected_collection in collections:
        col = collections[selected_collection]
        st.header(f"Collection: {col.name}")
        
        # Display collection info in a table format
        info = col.get_info()
        st.write("Collection Information:")
        table_html = """
        <table border="1" style="border-collapse: collapse; width: 50%;">
          <tr>
            <th style="padding: 8px;">Attribute</th>
            <th style="padding: 8px;">Value</th>
          </tr>
          <tr>
            <td style="padding: 8px;">Name</td>
            <td style="padding: 8px;">{name}</td>
          </tr>
          <tr>
            <td style="padding: 8px;">Created At</td>
            <td style="padding: 8px;">{created_at}</td>
          </tr>
          <tr>
            <td style="padding: 8px;">Number of Images</td>
            <td style="padding: 8px;">{num_images}</td>
          </tr>
        </table>
        """.format(name=info["Name"], created_at=info["Created At"], num_images=info["Number of Images"])
        st.markdown(table_html, unsafe_allow_html=True)
        
        # Provide option to delete the selected collection
        if st.button("Delete Collection"):
            del collections[selected_collection]
            st.success(f"Collection '{selected_collection}' deleted.")
            st.experimental_rerun()
        
        st.subheader("Manage Images")
        # File uploader to add images to the selected collection
        uploaded_files = st.file_uploader("Upload Images", type=["png", "jpg", "jpeg"], accept_multiple_files=True)
        if uploaded_files:
            success_count = 0
            for uploaded_file in uploaded_files:
                file_path = save_uploaded_file(uploaded_file)
                if col.add_image(file_path):
                    success_count += 1
                else:
                    st.error(f"Duplicate found: {uploaded_file.name} not added.")
            if success_count:
                st.success(f"{success_count} image(s) added successfully!")
            st.experimental_rerun()
        
        # Option to remove selected image(s)
        if col.images:
            image_basename_list = [os.path.basename(img) for img in col.images]
            image_to_remove = st.selectbox("Select Image to Remove", image_basename_list)
            if st.button("Remove Selected Image"):
                for img in col.images:
                    if os.path.basename(img) == image_to_remove:
                        if col.remove_image(img):
                            # Optionally, delete the file from disk
                            try:
                                os.remove(img)
                            except Exception as e:
                                st.error(f"Error removing file from disk: {e}")
                            st.success(f"Image {image_to_remove} removed.")
                            st.experimental_rerun()
                        else:
                            st.error("Image removal failed.")
                        break
        else:
            st.info("No images in this collection yet. Upload some images!")
        
        # Display images in a responsive grid using container width
        st.subheader("Image Grid")
        if col.images:
            grid_columns = 3
            cols = st.columns(grid_columns)
            for index, img_path in enumerate(col.images):
                with cols[index % grid_columns]:
                    try:
                        image = Image.open(img_path)
                        st.image(image, use_container_width=True, caption=os.path.basename(img_path))
                    except Exception as e:
                        st.error(f"Cannot display image: {e}")
    else:
        st.info("Please create a new collection from the sidebar.")
        
if __name__ == "__main__":
    main()
  

Application Details

Handling Collections

The application uses the concept of a Collection class that carries attributes about each image collection. When a collection is created, it is stored in the Streamlit session state, ensuring that sessions remain persistent. The sidebar provides a user-friendly interface that lists all collections and includes a text input to create new ones. Deleting a collection immediately removes it from the storage and refreshes the GUI.

Image Handling and Duplicate Prevention

Each collection maintains an internal list of image file paths. When users upload images, the code checks if the file name already exists in the collection, hence avoiding duplicates. Uploaded images are saved to a temporary directory; this is especially useful during development. In a production setting, enhancement is needed to ensure more robust file storage and management.

Responsive Image Grid

A responsive image grid is implemented using Streamlit's column layout. The images are displayed with captions arising from their file names. Note that the previously used use_column_width parameter is replaced by use_container_width to keep compliance with the latest Streamlit guidelines. This parameter ensures that images adapt appropriately to the container size, improving the user experience.

Additional Functionalities and Considerations

Immediate Interface Updates

The application leverages the st.experimental_rerun() function to ensure immediate updates whenever a change is made. This is especially useful after operations like adding or removing images or collections. Calling st.experimental_rerun() forces Streamlit to refresh the page so that the latest data is displayed.

Error Handling

Basic error handling is incorporated into the image removal and upload processes. For instance, when attempting to display images, exceptions are caught to notify the user if an image cannot be loaded. You can further enhance error handling to manage file I/O errors or permission issues depending on the production environment.

Future Enhancements

Possible future enhancements include:

  • Integration with a database for persistent storage of collections and image metadata.
  • Advanced management functionalities such as batch operations and drag-and-drop image ordering.
  • Improved file management to clean up temporary directories and better handle file paths.
  • Enhanced UI components and interaction patterns, such as image editing capabilities directly within the app.

Responsive Layout Table Example

Below is an HTML table example that summarizes the main components of the application:

Component Functionality
Collection Class Stores collection info like name, creation date and images. Prevents duplicate images.
Session State Manages all collections ensuring persistence during the session.
Image Upload & Storage Uploads images to a temporary directory and ensures duplicate names are not added.
Grid Display Displays images in a responsive grid using container width.

Conclusion

This comprehensive Streamlit application demonstrates how to effectively manage collections and images using a clean, modular design. By encapsulating collection features inside the Collection class and leveraging Streamlit's session state, dynamic and interactive user interfaces are ensured. The use of modern Streamlit features such as use_container_width provides a seamless and responsive experience. This solution serves as a solid foundation that can be further extended and customized based on production and user-specific requirements.


References


Recommended Further Queries


Last updated February 24, 2025

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI
Download Article
Delete Article