Ask me anything
Ithy Logo
Sign in to save

Streamlit Collection Manager Application

Interactive Web App to Manage Image Collections Using Python

scenic view of image gallery on a digital screen

Highlights

  • Comprehensive Features: Create, delete, list collections, and view full collection details including the number of images and creation dates.
  • Image Management: Seamlessly upload and display images within each individual collection.
  • Persistent and Organized: Uses JSON storage and directory structures for keeping track of collection metadata and images.

Overview

This project outlines a robust Streamlit application developed in Python to handle collections. Each collection is a container for images and has associated metadata such as the name, creation date, and number of images. The app allows for core functionalities:

  • Creating new collections by providing a unique collection name.
  • Deleting existing collections along with their images.
  • Listing all available collections on a sidebar for quick access.
  • Viewing detailed information for a selected collection including metadata and uploaded images.

The application leverages Streamlit’s interactive widgets for file uploads, text inputs, buttons, and dynamic re-rendering. It also utilizes JSON files for persisting collection metadata and a dedicated filesystem directory structure to store the images. In the sections below, you will find an in-depth explanation of each component along with a full example code.


Setting Up the Environment

Before you begin, ensure that you have installed the necessary Python packages. You need to have Python, Streamlit, and Pillow (for image processing) installed on your system. Run the following commands in your terminal:


# Install Streamlit
pip install streamlit

# Install Pillow for image handling
pip install pillow
  

Additionally, while this application uses a JSON file to store metadata, images are stored in specific directories. Ensure you have proper permissions to create files and directories in your project location.


Application Structure and Code Explanation

Directory and File Structure

The application uses a JSON file, "collections.json", for storing collection metadata, and creates a folder named "collections" where each collection gets its own subdirectory. The file structure is as follows:

File/Directory Description
streamlit_app.py Main Streamlit application script
collections.json JSON file storing metadata for collections
collections/ Directory where individual collection folders (with images) reside

This structure keeps the metadata and file storage separate, allowing for persistence even if the application is restarted.

Key Functions

The application is organized around several key functions:

  • load_collections(): This function loads collection metadata from the JSON file. If the file does not exist, it returns an empty dictionary.
  • save_collections(collections): Persists the current state of collections back into the JSON file.
  • create_collection(name): Handles creation of a new collection by assigning it a unique name, capturing its creation date, and initializing the images list. It also creates the corresponding directory for the collection.
  • delete_collection(name): Deletes an existing collection: removes the metadata and deletes the directory containing all its images.
  • add_images_to_collection(collection_name, uploaded_files): Processes image uploads for a specific collection. It saves the image files into the correct directory and updates the collection metadata by adding file names to the images list.
  • display_collection_info(collection_name): Shows the details of the selected collection including its name, creation date, and the number of images.

The Main Application Workflow

The main function encapsulates the core workflow of the app:

  1. Title and Sidebar Navigation: The title of the app and a sidebar menu allow users to create new collections, select existing collections from a dropdown, and delete collections as needed.
  2. Creation and Deletion: Input forms allow for creating a collection (by entering a unique name) and deleting a selected collection.
  3. Displaying Collection Details: When a collection is selected, the app displays metadata such as the creation date and the number of images present in the collection.
  4. Uploading and Displaying Images: Users can upload one or more image files to the chosen collection. The images are then visually displayed in a grid format, making use of Streamlit’s columns functionality to arrange images neatly.

Complete Code Implementation

Below is the complete Python script for the Streamlit application. This code integrates functions for managing collections and images.


# Import necessary modules
import streamlit as st
import os
import json
import datetime
from PIL import Image
import shutil

# Set constants for metadata file and storage folder
COLLECTIONS_FILE = 'collections.json'
COLLECTIONS_DIR = 'collections'

# Ensure the collections directory exists
os.makedirs(COLLECTIONS_DIR, exist_ok=True)

def load_collections():
    """
    Load collections from the JSON file.
    If the file does not exist, return an empty dictionary.
    """
    try:
        with open(COLLECTIONS_FILE, 'r') as file:
            return json.load(file)
    except FileNotFoundError:
        return {}

def save_collections(collections):
    """
    Save the collections dictionary to the JSON file.
    """
    with open(COLLECTIONS_FILE, 'w') as file:
        json.dump(collections, file, indent=4)

def create_collection(name):
    """
    Create a new collection with the specified name.
    Checks for name uniqueness and creates a new directory for the collection.
    """
    collections = load_collections()
    if name in collections:
        st.error(f"Collection '{name}' already exists!")
        return False

    # Create collection metadata
    collections[name] = {
        'name': name,
        'created_at': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        'images': []
    }
    
    # Create a directory to store images for this collection
    collection_path = os.path.join(COLLECTIONS_DIR, name)
    os.makedirs(collection_path, exist_ok=True)
    
    save_collections(collections)
    st.success(f"Collection '{name}' created successfully!")
    return True

def delete_collection(name):
    """
    Delete the collection with the given name.
    It removes both the metadata and the collection's folder containing images.
    """
    collections = load_collections()
    if name not in collections:
        st.error(f"Collection '{name}' does not exist!")
        return False

    # Remove the collection metadata
    del collections[name]
    
    # Remove the collection folder and its contents
    collection_path = os.path.join(COLLECTIONS_DIR, name)
    shutil.rmtree(collection_path, ignore_errors=True)
    
    save_collections(collections)
    st.success(f"Collection '{name}' deleted successfully!")
    return True

def add_images_to_collection(collection_name, uploaded_files):
    """
    Add images to a specific collection.
    Saves each uploaded file in the corresponding collection folder and updates metadata.
    """
    collections = load_collections()
    if collection_name not in collections:
        st.error(f"Collection '{collection_name}' does not exist!")
        return False

    collection_path = os.path.join(COLLECTIONS_DIR, collection_name)
    for uploaded_file in uploaded_files:
        # Create a unique filename based on current count and original filename
        filename = f"{len(collections[collection_name]['images'])}_{uploaded_file.name}"
        file_path = os.path.join(collection_path, filename)
        
        # Save the file
        with open(file_path, "wb") as file:
            file.write(uploaded_file.getbuffer())
            
        # Update collection metadata with the new image filename
        collections[collection_name]['images'].append(filename)
    
    save_collections(collections)
    st.success(f"Images added to collection '{collection_name}'!")
    return True

def main():
    # Title of the application
    st.title("Image Collection Manager")
    
    # Sidebar: Create and delete collection actions
    st.sidebar.header("Collection Actions")
    new_collection_name = st.sidebar.text_input("Create New Collection")
    if st.sidebar.button("Create Collection"):
        if new_collection_name.strip():
            create_collection(new_collection_name.strip())
        else:
            st.sidebar.error("Please provide a valid name.")

    # Load existing collections metadata
    collections = load_collections()

    # Sidebar: Select an existing collection to view or manage
    selected_collection = st.sidebar.selectbox("Select Collection", [""] + list(collections.keys()))
    if selected_collection:
        if st.sidebar.button("Delete Collection"):
            delete_collection(selected_collection)
            st.experimental_rerun()

    # If a collection is selected, display its details
    if selected_collection:
        st.header(f"Collection: {selected_collection}")
        collection_info = collections[selected_collection]
        col1, col2 = st.columns(2)
        with col1:
            st.write(f"<b>Created At:</b> {collection_info['created_at']}", unsafe_allow_html=True)
        with col2:
            st.write(f"<b>Number of Images:</b> {len(collection_info['images'])}", unsafe_allow_html=True)

        # Form for uploading images to the collection
        st.subheader("Upload Images")
        uploaded_files = st.file_uploader("Select Images", type=['jpg', 'jpeg', 'png'], accept_multiple_files=True)
        if uploaded_files:
            add_images_to_collection(selected_collection, uploaded_files)

        # Display images in a dynamic grid layout
        st.subheader("Images in the Collection")
        collection_path = os.path.join(COLLECTIONS_DIR, selected_collection)
        images = collection_info['images']
        if images:
            # Dynamically create columns for a grid display (4 images per row)
            cols = st.columns(4)
            for idx, img_name in enumerate(images):
                img_path = os.path.join(collection_path, img_name)
                try:
                    img = Image.open(img_path)
                    cols[idx % 4].image(img, caption=img_name, use_column_width=True)
                except Exception as error:
                    st.error(f"Error loading {img_name}: {error}")
        else:
            st.info("No images in this collection. Upload images to see them here.")

if __name__ == "__main__":
    main()
  

This complete code snippet brings together all the functionalities. Once you run this code using the command below, the application will start in your browser:


streamlit run streamlit_app.py
  

Deep Dive into Functionality

Collection Metadata Management

The metadata for each collection is stored in a JSON file ("collections.json"). This file not only holds information such as the creation timestamp and name of the collection, but also a list of images that belong to the collection. This approach ensures that even if the application shuts down, all metadata remains intact and can be reloaded during the next run.

The load_collections() and save_collections() functions abstract the process of reading from and writing to this file, enabling the seamless persistence of state.

Image Storage and Display

The application stores images on disk within a subdirectory named after the collection. This not only organizes the files effectively but also ensures that file handling (saving, reading, and deletion) can be done with minimal conflicts. Uploaded images are saved with a unique naming format that incorporates the current count of images—this prevents overwrites and keeps track of images accurately.

In order to display images, the program uses the Python Pillow library to load image files which are then passed to Streamlit’s st.image() function. The images are arranged in a grid format using Streamlit’s column layout, ensuring a neat and organized presentation.

Interactive UI and User Experience

Leveraging Streamlit's interactive widgets, the application offers a user-friendly interface. The sidebar is used for executing collection actions, making it easy for users to switch between collections, create new ones, or delete unwanted ones. Central panels display details and images based on user selection.

Additionally, when users upload images, success messages provide feedback so that the user knows their actions have been successfully executed. Conditional rendering is used to only display detailed information when a collection is selected. This helps keep the interface uncluttered and focused on the current task.

Understanding the Code Flow

Initialization

On starting the app, the collections directory and metadata store are prepared. If the JSON file does not exist on the first run, the functions adapt by creating a new empty metadata dictionary.

Creating and Deleting Collections

The actions for creating and deleting collections are triggered via buttons in the sidebar. When creating, the function verifies that the entered name is unique and only then proceeds to create a directory and metadata entry. Deletion removes both the metadata and the physical directory.

Image Upload and Display

Uploading images is handled in a form that supports multiple files. Each image file is saved into the respective collection directory, and the metadata is updated accordingly. The grid display uses a dynamic column layout enabling 4 images per row, which reorders images gracefully when the count is not a multiple of four.

This sequential flow ensures that user interactions are intuitive and every action is reflected immediately in the UI, thanks to Streamlit’s fast re-rendering of updates.

Additional Enhancements and Considerations

While the provided code meets the basic functionalities required for creating, deleting, and displaying collections with images, there are several ways you could extend this application further:

  • Image Deletion: Implement a function to remove individual images from a collection. This would involve updating both the filesystem (by deleting the file) and the JSON metadata.
  • Edit Collection Details: Allow the renaming or reordering of images in existing collections by adding an editing interface.
  • Search and Filtering: Include a search feature to quickly locate a collection by name or filter images based on tags or creation date.
  • Responsive Layout: Enhance the user interface with custom CSS or additional Streamlit components to better handle varying screen sizes or interactive dashboards.
  • Error Handling: Add more robust error management, ensuring that file read/write errors are gracefully handled and appropriate error messages are provided.

These improvements would not only provide better functionality but would also polish the user experience, making your application ready for larger-scale use or even deployment in a production environment.

Table of Application Components

Component Description
Streamlit Sidebar User interactions for creating, selecting, and deleting collections
JSON Metadata Store Persists collection data including names, creation dates, and image lists
Filesystem Directories Holds image files in separate folders organized by collection
Image Grid Display Uses Streamlit columns to display images in a responsive grid
Error and Success Notifications Provides immediate feedback to enhance user experience

Conclusion and Final Thoughts

In summary, the Streamlit based Collection Manager application harnesses Python’s simplicity and Streamlit’s interactivity to provide a complete solution for managing image collections. With functionalities to create, delete, and view collections—and with a user-friendly interface for uploading and displaying images—this application offers a solid foundation that you can further build upon with additional features like image deletion, collection editing, and enhanced error handling.

By following the comprehensive code guidance and best practices outlined here, you now have a powerful tool at your disposal for managing image collections effectively. This modular, extensible design not only meets the requirements of basic collection management but also leaves room for significant enhancements that can make your application even more robust and suitable for real-world scenarios.


References

Recommended Queries

docs.streamlit.io
st.image - Streamlit Docs

Last updated February 24, 2025

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

Ask Ithy AI