DenisT's picture
fix single image not found ocr error
f0b0469
import os
import io
import zipfile
from typing import List, Tuple, Union
import numpy as np
from PIL import Image
import gradio as gr
from utils.langs import languages
from main import predict
language_choices = [(name.title(), code) for name, code in languages.items()]
def extract_path(data) -> Union[str, None]:
"""
Recursively extract a string path from various Gradio data formats (dict, list, string).
"""
if isinstance(data, str):
return data
if isinstance(data, (list, tuple)) and len(data) > 0:
return extract_path(data[0])
if isinstance(data, dict):
# Priority keys for different Gradio versions/components
for key in ['path', 'image', 'name', 'url', 'value']:
val = data.get(key)
if val:
res = extract_path(val)
if res: return res
return None
def process_images(
images: List, source_lang: str, target_lang: str
) -> Tuple[List[np.ndarray], str]:
"""
Process multiple images and return translated images and status message.
"""
if not images:
return [], "No images uploaded"
translated_images = []
for idx, img_data in enumerate(images):
try:
img_path = extract_path(img_data)
if not img_path or not os.path.exists(img_path):
print(f"Warning: Could not find image at {img_path}")
continue
img = Image.open(img_path).convert("RGB")
image_np = np.array(img)
# Translate the image
translated_image = predict(
image_np, source_lang=source_lang, target_lang=target_lang
)
if translated_image is not None:
translated_images.append(translated_image)
else:
print(f"Warning: Image {idx + 1} translation failed")
except Exception as e:
print(f"Error processing image {idx + 1}: {str(e)}")
continue
status = f"Successfully translated {len(translated_images)} out of {len(images)} images"
return translated_images, status
def create_zip_file(*args) -> str:
"""
Create a ZIP file containing all translated images from cache.
"""
global translated_images_cache
if not translated_images_cache:
return None
zip_path = "translated_manga_images.zip"
with zipfile.ZipFile(zip_path, 'w') as zipf:
for idx, img_array in enumerate(translated_images_cache):
# Convert numpy array to PIL Image
img = Image.fromarray(img_array.astype('uint8'))
# Save to bytes buffer
img_buffer = io.BytesIO()
img.save(img_buffer, format='PNG')
img_buffer.seek(0)
# Add to zip
zipf.writestr(f"translated_image_{idx + 1}.png", img_buffer.getvalue())
return zip_path
# Global variable to store translated images for download
translated_images_cache = []
def process_and_cache(images, source_lang, target_lang):
"""Process images and cache results for download."""
global translated_images_cache
if not images:
return None, "Please upload at least one image", gr.update(visible=False)
translated_images, status = process_images(images, source_lang, target_lang)
translated_images_cache = translated_images
if translated_images:
return (
translated_images,
status,
gr.update(visible=True, interactive=True), # download button
)
else:
return None, status, gr.update(visible=False, interactive=False)
# Custom CSS for better styling
custom_css = """
.image-container {
height: 600px !important;
}
.gallery-container {
min-height: 400px;
}
.example-gallery img {
cursor: pointer;
border: 2px solid transparent;
transition: border 0.2s;
}
.example-gallery img:hover {
border: 2px solid #2563eb;
}
"""
with gr.Blocks(css=custom_css, title="Manga Translator") as demo:
gr.Markdown(
"""
<div style="display: flex; align-items: center; flex-direction: row; justify-content: center; margin-bottom: 20px; text-align: center;">
<a href="https://github.com/Detopall/manga-translator" target="_blank" rel="noopener noreferrer" style="text-decoration: none;">
<h1 style="display: inline; margin-left: 10px; text-decoration: underline;">Manga Translator</h1>
</a>
</div>
<p style="text-align: center; color: #666;">Upload manga images, select languages, and get instant translations with GPU acceleration!</p>
"""
)
with gr.Row():
with gr.Column(scale=1):
with gr.Accordion("πŸ“š Example Gallery - Click images to select", open=True):
examples_paths = [f"./examples/ex{i}.jpg" for i in range(1, 9)]
examples_paths = [p for p in examples_paths if os.path.exists(p)]
example_selector = gr.Gallery(
value=examples_paths,
label="Select multiple images from examples below",
columns=4,
height=250,
object_fit="contain",
allow_preview=False,
interactive=False,
elem_classes="example-gallery"
)
# Use a File component for the final list of images (uploaded or selected)
image_input = gr.File(
label="πŸ“ Selected Images (Upload more here)",
file_count="multiple",
file_types=["image"],
elem_id="image_input"
)
clear_btn = gr.Button("πŸ—‘οΈ Clear Selection", variant="secondary")
# Language selection
with gr.Row():
source_language_dropdown = gr.Dropdown(
choices=language_choices,
label="Source Language",
value="ja-JP",
)
target_language_dropdown = gr.Dropdown(
choices=language_choices,
label="Target Language",
value="en-GB",
)
submit_button = gr.Button("πŸš€ Translate All", variant="primary", size="lg")
status_text = gr.Textbox(label="Status", interactive=False, lines=2)
with gr.Column(scale=1):
# Image gallery for results
image_output = gr.Gallery(
label="Translated Results",
show_label=True,
columns=2,
rows=2,
height=600,
object_fit="contain",
preview=True
)
# Download button and file output
download_button = gr.Button(
"πŸ“¦ Download All as ZIP",
visible=False,
variant="secondary",
size="lg"
)
download_file = gr.File(label="Ready for download", visible=False)
# Selection logic: Click example -> Add to file list
def add_from_example(evt: gr.SelectData, current_files):
# Extract the path from the selection event
new_path = extract_path(evt.value)
if current_files is None:
current_files = []
# Build clean list of unique string paths
paths = []
# First add existing files
for f in current_files:
p = extract_path(f)
if p and p not in paths:
paths.append(p)
# Then add the new selection if it's unique
if new_path and new_path not in paths:
paths.append(new_path)
return paths
example_selector.select(
add_from_example,
inputs=image_input,
outputs=image_input
)
clear_btn.click(lambda: [], outputs=image_input)
# Translation logic
submit_button.click(
process_and_cache,
inputs=[image_input, source_language_dropdown, target_language_dropdown],
outputs=[image_output, status_text, download_button]
)
# Download functionality
download_button.click(
fn=create_zip_file,
inputs=[],
outputs=download_file
).then(
lambda: gr.update(visible=True),
outputs=download_file
)
if __name__ == "__main__":
demo.launch()