(Fixes download issue)
- filename: used as download filename
"""
parts = []
parts.append("")
parts.append("
")
# table header
parts.append(
""
"| Source | "
"Score | "
"
"
)
parts.append("")
# NEW UNPACKING: (data_uri, download_path, filename, score)
for (data_uri, download_path, filename, score) in entries:
# image cell - no outline, image constrained to max-height:256px, object-fit:contain
# link points to download_path. The img src is the data URI.
href = download_path or "#"
# src is now the data URI for guaranteed display.
img_html = f"
"
score_html = f"{score:.3f}
"
parts.append("")
parts.append(f"| {img_html} | ")
parts.append(f"{score_html} | ")
parts.append("
")
parts.append("
")
return "\n".join(parts)
# ---------------------------------------------
# --- MODIFIED FUNCTION LOGIC ---
def run_classify(
uploaded_image_path,
url_input,
batch_files,
batch_urls_text,
model_key,
) -> str:
"""
Returns HTML for the custom table. Uses original file paths for images.
Works for single and batch modes.
"""
images_to_classify = []
original_paths = [] # Original paths for filename reference
# Batch files (filepaths)
if batch_files:
for f in batch_files:
try:
img = Image.open(f).convert("RGB")
except Exception:
continue
images_to_classify.append(img)
original_paths.append(f)
# Batch URLs
if batch_urls_text:
for line in batch_urls_text.splitlines():
line = line.strip()
if not line:
continue
saved_path, _ = download_url_to_temp(line)
if saved_path:
try:
img = Image.open(saved_path).convert("RGB")
except Exception:
continue
images_to_classify.append(img)
original_paths.append(saved_path)
pipe = load_model(model_key)
# Batch mode
if images_to_classify:
scores = classify_images(images_to_classify, pipe)
entries = []
for i, score in enumerate(scores):
img = images_to_classify[i]
# 1. Create Data URI for display (Fixes "text not image")
data_uri = pil_to_data_uri(img)
# 2. Save the full-res image to a new temp path for download/full-view.
# This is the full, uncorrupted image. (Fixes "corrupted/smaller on click")
temp_download_path = os.path.join(tempfile.gettempdir(), f"download_{uuid.uuid4().hex}.jpg")
img.save(temp_download_path, "JPEG", quality=95) # Save full quality
# Get original filename for download attribute
src_path = original_paths[i] if i < len(original_paths) else None
filename = os.path.basename(src_path) if src_path else f"{uuid.uuid4().hex}.jpg"
# Pass the new structure: (data_uri, download_path, filename, score)
entries.append((data_uri, temp_download_path, filename, float(score)))
return build_results_table_html(entries)
# Single-image mode: prefer URL input, then upload
img = None
src_path = None
if url_input:
saved_path, _ = download_url_to_temp(url_input.strip())
if saved_path:
try:
img = Image.open(saved_path).convert("RGB")
src_path = saved_path
except Exception:
img = None
src_path = None
if img is None and uploaded_image_path:
# uploaded_image_path is a filepath string
try:
img = Image.open(uploaded_image_path).convert("RGB")
src_path = uploaded_image_path
except Exception:
img = None
src_path = None
if img is None:
return "No valid image(s) provided. Please upload or supply a URL.
"
scores = classify_images([img], pipe)
score = float(scores[0]) if scores else 0.0
# 1. Create Data URI for display
data_uri = pil_to_data_uri(img)
# 2. Save the full-res image to a new temp path for download/full-view.
temp_download_path = os.path.join(tempfile.gettempdir(), f"download_{uuid.uuid4().hex}.jpg")
img.save(temp_download_path, "JPEG", quality=95)
filename = os.path.basename(src_path) if src_path else f"{uuid.uuid4().hex}.jpg"
entries = [(data_uri, temp_download_path, filename, score)] # Use the new temp path
return build_results_table_html(entries)
# ---------------------------------------------
# Build the Gradio UI with CSS tweaks
css = """
/* clamp the left upload image preview to 40vh */
/* make left column scroll if content would grow too tall, and limit to viewport */
#left_column {
max-height: 90vh; /* entire column won't exceed viewport*/
overflow: auto;
}
/* clamp the upload preview to 40% of the viewport height */
#left_input_image img,
#left_input_image canvas {
max-height: 40vh !important;
height: auto !important;
width: auto !important;
object-fit: contain !important;
display: block !important;
margin: 0 auto !important;
}
/* results table tweaks kept from before */
#results_table_container table th {
border-color: rgba(255,255,255,0.6) !important;
}
#results_table_container table td {
border-color: rgba(255,255,255,0.06) !important;
}
#results_table_container img {
outline: none !important;
border: none !important;
box-shadow: none !important;
max-height: 256px;
}
"""
with gr.Blocks(title="Aesthetic Shadow - Anime Image Quality Classifier (CPU)", css=css) as demo:
gr.Markdown("Aesthetic Shadow - Anime Image Quality Classifier (running on CPU | ETA for single image: ~50s (fp16 & fp32 are likely same speed on cpu))")
gr.Markdown("All Aesthetic Shadow models are by shadowlilac. V2 is using reuploads by other people.")
with gr.Row():
with gr.Column(scale=2, elem_id="left_column"):
gr.Markdown("### Input")
with gr.Tabs():
with gr.TabItem("Single"):
uploaded_image = gr.Image(label="Drop or click to upload", type="filepath", elem_id="left_input_image")
url_input = gr.Textbox(label="Image URL (optional)", placeholder="https://...", lines=1)
# it takes reaaaaally long and there is a bug i think where it will take images from both tabs instead of just the active one
with gr.TabItem("Batch"):
batch_files = gr.File(label="Upload multiple images (batch)", file_count="multiple", type="filepath")
batch_urls_text = gr.Textbox(label="Batch URLs (one per line)", placeholder="https://...", lines=4)
with gr.Column(scale=1):
gr.Markdown("### Model & Run")
model_dropdown = gr.Dropdown(
choices=[k for k in MODEL_CHOICES.keys() if k != "default"],
value=DEFAULT_MODEL_KEY,
label="Model Selection",
)
run_button = gr.Button("Run", variant="primary")
gr.Markdown("### Results")
result_table_html = gr.HTML("Results will appear here after running.
")
def run_handler(up_img, url_txt, b_files, b_urls, model_key):
html = run_classify(up_img, url_txt, b_files, b_urls, model_key)
return html
run_button.click(
fn=run_handler,
inputs=[uploaded_image, url_input, batch_files, batch_urls_text, model_dropdown],
outputs=[result_table_html],
)
if __name__ == "__main__":
demo.launch()