| import streamlit as st |
| import os |
| import zipfile |
| import csv |
| from PIL import Image, ImageFilter |
| import base64 |
| import datetime |
| from gradio_client import Client |
|
|
| if 'blur_option' not in st.session_state: |
| st.session_state.blur_option = True |
|
|
| |
| client_nsfw = Client("https://ozoneasai-falconsai-nsfw-image-detection.hf.space/--replicas/hrcrr/") |
|
|
| |
| uploaded_files = st.file_uploader("画像ファイルをアップロードしてください", type=["jpg", "jpeg", "png"], accept_multiple_files=True) |
|
|
| |
| if 'page' not in st.session_state: |
| st.session_state.page = 1 |
|
|
| |
| if 'blur_option' not in st.session_state: |
| st.session_state.blur_option = st.checkbox("NSFW画像にBlurをかける", value=st.session_state.blur_option, key="blur_toggle") |
|
|
| |
| if 'sort_option' not in st.session_state: |
| st.session_state.sort_option = {"column": "timestamp", "ascending": True} |
|
|
| |
| def get_binary_file_downloader_html(file_path, label="Download"): |
| with open(file_path, 'rb') as f: |
| data = f.read() |
| b64 = base64.b64encode(data).decode() |
| href = f'<a href="data:file/csv;base64,{b64}" download="{os.path.basename(file_path)}">{label}</a>' |
| return href |
|
|
| |
| def get_gradio_nsfw_prediction(image_path): |
| result = client_nsfw.predict(image_path, api_name="/predict") |
| return result[0]["label"] if result and result[0] and "label" in result[0] else "unknown" |
|
|
| |
| def save_uploaded_files(uploaded_files): |
| if not os.path.exists("temp"): |
| os.makedirs("temp") |
| |
| for uploaded_file in uploaded_files: |
| file_path = os.path.join("temp", uploaded_file.name) |
| with open(file_path, "wb") as f: |
| f.write(uploaded_file.getbuffer()) |
| |
| |
| gradio_nsfw_prediction = get_gradio_nsfw_prediction(file_path) |
| |
| |
| timestamp = datetime.datetime.now() |
|
|
| |
| with open("temp/index.csv", mode='a', newline='', encoding='utf-8') as csv_file: |
| csv_writer = csv.writer(csv_file) |
| csv_writer.writerow([file_path, gradio_nsfw_prediction, timestamp]) |
|
|
| |
| def apply_blur(image_path): |
| img = Image.open(image_path) |
| img = img.filter(ImageFilter.GaussianBlur(radius=5)) |
| return img |
|
|
| |
| def paginate_files(files, page, files_per_page): |
| start_index = (page - 1) * files_per_page |
| end_index = start_index + files_per_page |
| return files[start_index:end_index] |
|
|
| |
| def display_images(images, rows): |
| for i, file_path in enumerate(images): |
| file_ext = os.path.splitext(file_path)[1].lower() |
|
|
| |
| if os.path.exists("temp/index.csv") and i < len(rows): |
| gradio_nsfw_prediction = rows[i][1] |
| timestamp = rows[i][2] |
|
|
| st.write(f"**Prediction for {os.path.basename(file_path)} (NSFW):** {gradio_nsfw_prediction}") |
| st.write(f"**Timestamp:** {timestamp}") |
|
|
| if st.session_state.blur_option and gradio_nsfw_prediction.lower() == "nsfw": |
| blurred_img = apply_blur(file_path) |
| st.image(blurred_img, caption=os.path.basename(file_path), use_column_width=True) |
| else: |
| if file_ext in [".jpg", ".png"]: |
| st.image(Image.open(file_path), caption=os.path.basename(file_path), use_column_width=True) |
| col1, col2 = st.columns([4, 1]) |
| with col1: |
| if file_ext in [".jpg", ".png"]: |
| st.image(Image.open(file_path), caption=os.path.basename(file_path), use_column_width=True) |
| with col2: |
| if col2.button("削除", key=file_path): |
| os.remove(file_path) |
| |
| st.experimental_rerun() |
|
|
| |
| if uploaded_files: |
| save_uploaded_files(uploaded_files) |
|
|
| files_per_page = 20 |
| num_pages = (len(os.listdir("temp")) - 1) // files_per_page + 1 |
|
|
| col1, col2 = st.columns(2) |
| with col1: |
| if st.button("前へ", key="prev_page"): |
| st.session_state.page = max(1, st.session_state.page - 1) |
| with col2: |
| if st.button("次へ", key="next_page"): |
| st.session_state.page = min(num_pages, st.session_state.page + 1) |
|
|
| selected_page = st.number_input( |
| "移動するページを指定してください", |
| min_value=1, |
| max_value=num_pages, |
| value=max(1, min(st.session_state.page, num_pages)), |
| key="selected_page" |
| ) |
| if selected_page != st.session_state.page: |
| st.session_state.page = selected_page |
|
|
| st.write(f"現在のページ: {st.session_state.page}") |
|
|
| |
| with open("temp/index.csv", mode='r', newline='', encoding='utf-8') as csv_file: |
| csv_reader = csv.reader(csv_file) |
| rows = list(csv_reader) |
|
|
| |
| current_page_files = paginate_files([row[0] for row in rows], st.session_state.page, files_per_page) |
| st.write("ファイル一覧:") |
| display_images(current_page_files, rows) |
|
|
| |
|
|
|
|
| st.session_state.blur_option = st.checkbox("NSFW画像にBlurをかける", value=st.session_state.blur_option) |
|
|
| |
| if st.button("CSVに保存"): |
| csv_filename = "gradio_predictions_and_timestamps.csv" |
| with open(csv_filename, mode='w', newline='', encoding='utf-8') as csv_file: |
| csv_writer = csv.writer(csv_file) |
| csv_writer.writerow(['ファイル名', 'NSFWの予測', '作成時間']) |
| for row in rows: |
| csv_writer.writerow([row[0], row[1], row[2]]) |
|
|
| st.markdown(get_binary_file_downloader_html(csv_filename, label="CSVをダウンロード"), unsafe_allow_html=True) |
|
|
| |
| if st.button("ファイルを一括ダウンロード"): |
| zip_filename = "files.zip" |
| with zipfile.ZipFile(zip_filename, "w") as zipf: |
| for file_path in [row[0] for row in rows]: |
| zipf.write(file_path, os.path.basename(file_path)) |
|
|
| st.markdown(get_binary_file_downloader_html(zip_filename, label="Zipファイルをダウンロード"), unsafe_allow_html=True) |
|
|
| st.success("ファイルがアップロードされました。このページのURLを他のクライアントと共有してください。") |
|
|