| import streamlit as st |
| import pandas as pd |
| import requests |
| from PIL import Image, ImageStat |
| from io import BytesIO |
| import numpy as np |
| import time |
| import base64 |
|
|
| st.set_page_config(page_title="Amazon Image Optimizer", layout="wide") |
|
|
| st.title("Amazon Image Optimizer") |
| st.markdown(""" |
| This app helps reorganize your product images to comply with Amazon's listing requirements. |
| Upload your CSV file containing SKU and image URLs, and the app will: |
| 1. Detect which image has a white background |
| 2. Ensure the white background image is placed in the image1 column |
| 3. Allow you to download the reorganized CSV |
| """) |
|
|
| def is_white_background(image_url, threshold=240): |
| """Determine if an image has a predominantly white background""" |
| try: |
| response = requests.get(image_url, timeout=5) |
| img = Image.open(BytesIO(response.content)).convert('RGB') |
| |
| |
| width, height = img.size |
| border_width = int(width * 0.1) |
| border_height = int(height * 0.1) |
| |
| |
| left_edge = img.crop((0, 0, border_width, height)) |
| right_edge = img.crop((width - border_width, 0, width, height)) |
| top_edge = img.crop((0, 0, width, border_height)) |
| bottom_edge = img.crop((0, height - border_height, width, height)) |
| |
| |
| edges = [left_edge, right_edge, top_edge, bottom_edge] |
| edge_stats = [ImageStat.Stat(edge) for edge in edges] |
| edge_means = [stat.mean for stat in edge_stats] |
| |
| |
| is_white = all(all(channel > threshold for channel in mean) for mean in edge_means) |
| |
| |
| overall_stat = ImageStat.Stat(img) |
| overall_brightness = sum(overall_stat.mean) / 3 |
| |
| return is_white and overall_brightness > threshold |
| except Exception as e: |
| st.error(f"Error processing image: {e}") |
| return False |
|
|
| def process_csv(df): |
| """Process the dataframe to reorder images putting white background first""" |
| progress_bar = st.progress(0) |
| status_text = st.empty() |
| |
| |
| result_df = df.copy() |
| |
| |
| image_columns = [col for col in df.columns if col.startswith('image') and col != 'image1'] |
| |
| for i, row in df.iterrows(): |
| sku = row['sku'] |
| status_text.text(f"Processing SKU: {sku} ({i+1}/{len(df)})") |
| |
| white_bg_found = False |
| img_urls = [] |
| white_bg_url = None |
| |
| |
| if pd.notna(row['image1']) and is_white_background(row['image1']): |
| white_bg_found = True |
| white_bg_url = row['image1'] |
| |
| |
| for col in image_columns: |
| if pd.notna(row[col]): |
| if not white_bg_found and is_white_background(row[col]): |
| white_bg_found = True |
| white_bg_url = row[col] |
| else: |
| img_urls.append(row[col]) |
| |
| |
| if white_bg_found: |
| |
| result_df.at[i, 'image1'] = white_bg_url |
| |
| |
| remaining_img_count = 0 |
| for idx, url in enumerate(img_urls, start=0): |
| col_name = f'image{idx+2}' |
| if col_name in result_df.columns: |
| result_df.at[i, col_name] = url |
| remaining_img_count += 1 |
| |
| progress_bar.progress((i + 1) / len(df)) |
| |
| status_text.text("Processing complete!") |
| return result_df |
|
|
| def get_download_link(df, filename): |
| """Generate a download link for the dataframe""" |
| |
| csv = df.to_csv(index=False, float_format='%.0f') |
| b64 = base64.b64encode(csv.encode()).decode() |
| href = f'data:file/csv;base64,{b64}' |
| return href |
|
|
| |
| uploaded_file = st.file_uploader("Upload your product CSV file", type=["csv"]) |
|
|
| if uploaded_file is not None: |
| |
| |
| df = pd.read_csv(uploaded_file, dtype={'sku': str}) |
| |
| st.subheader("Original Data Preview") |
| st.dataframe(df.head()) |
| |
| |
| required_columns = ['sku', 'image1'] |
| missing_columns = [col for col in required_columns if col not in df.columns] |
| |
| if missing_columns: |
| st.error(f"Missing required columns: {', '.join(missing_columns)}") |
| else: |
| if st.button("Process Images"): |
| with st.spinner("Processing images..."): |
| result_df = process_csv(df) |
| |
| st.subheader("Results") |
| st.dataframe(result_df.head()) |
| |
| |
| dl_link = get_download_link(result_df, "amazon_optimized_images.csv") |
| st.markdown(f'<a href="{dl_link}" download="amazon_optimized_images.csv">Download Processed CSV</a>', unsafe_allow_html=True) |
| |
| |
| total_rows = len(df) |
| white_bg_found = sum(1 for _, row in result_df.iterrows() if pd.notna(row['image1'])) |
| |
| st.subheader("Summary") |
| st.write(f"Total products processed: {total_rows}") |
| st.write(f"Products with white background images: {white_bg_found}") |
| st.write(f"Products missing white background images: {total_rows - white_bg_found}") |
|
|
| |
| st.sidebar.header("Instructions") |
| st.sidebar.markdown(""" |
| ### CSV Format Requirements |
| Your CSV file should include: |
| - A 'sku' column with product identifiers |
| - Image columns named 'image1', 'image2', etc. containing image URLs |
| |
| ### How It Works |
| The app analyzes the edges of each image to detect white backgrounds. |
| It then reorganizes the URLs to ensure white background images are in the image1 position. |
| |
| ### Tips |
| - Ensure your image URLs are publicly accessible |
| - The process may take some time for large datasets |
| - For best results, make sure product images have clear contrasts between product and background |
| """) |
|
|