### Set up Environment for Manga Image Translator (Python) Source: https://github.com/zyddnys/manga-image-translator/blob/main/run_as_colab.ipynb This snippet clones the repository, navigates into the project directory, and installs the necessary Python dependencies from the requirements file. It's designed for environments like Google Colab. ```python # Set up the environment. !git clone https://github.com/zyddnys/manga-image-translator %cd manga-image-translator/ !python -m pip install -r requirements.txt ``` -------------------------------- ### Install and Launch MangaStudio GUI Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Instructions for installing the necessary Python dependencies and launching the MangaStudio graphical user interface. The GUI supports drag-and-drop functionality and visual configuration of translation settings. ```bash # Install GUI dependencies pip install PySide6 Pillow # Launch the GUI application python MangaStudioMain.py ``` -------------------------------- ### Start Docker Compose Services Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Starts the services defined in the docker-compose.yml file in detached mode. This command is used to deploy and run the manga-translator application. ```bash # Start services docker-compose up -d ``` -------------------------------- ### Start Manga Image Translator Web Server Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Launch the web server for Manga Image Translator, which provides both a user interface and REST API endpoints. Supports GPU acceleration and automatic translator instance startup. ```bash # Start web server with GPU support cd server python main.py --use-gpu --host 0.0.0.0 --port 8000 # Start with automatic translator instance python main.py --use-gpu --start-instance # The web UI is available at: http://127.0.0.1:8000 # API documentation at: http://127.0.0.1:8000/docs # API endpoint at: http://127.0.0.1:8001 ``` -------------------------------- ### Run Manga Image Translator Web Interface with GPU (Python) Source: https://github.com/zyddnys/manga-image-translator/blob/main/run_as_colab.ipynb This snippet demonstrates how to run the Manga Image Translator in web mode using a GPU. It obtains a proxy URL for accessing the web interface and starts the translator. Ensure a GPU is selected at runtime in environments like Google Colab. ```python # Run with colab. GPU must be selected at runtime! from google.colab.output import eval_js url = eval_js("google.colab.kernel.proxyPort(5003)") print('Open the link to use manga-image-translator! -> ', url) !python -m manga_translator --verbose --mode web --use-gpu ``` -------------------------------- ### Install Testing Dependencies with Pip Source: https://github.com/zyddnys/manga-image-translator/blob/main/test/README.md Installs the necessary packages for running tests, including pytest and pytest-asyncio. These are essential for the testing framework. ```bash pip install pytest pytest-asyncio ``` -------------------------------- ### Configure Pre/Post Translation Dictionaries Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Examples of text replacement dictionaries for pre- and post-translation processing. Pre-dictionaries fix OCR errors before translation, while post-dictionaries standardize translated output and honorifics. ```text # dict/pre_dict.txt - Applied before translation (fix OCR errors) # Format: pattern replacement # Fix common OCR mistakes 力ノレ カル カ力 カカ [00][Oo] oo # Remove unwanted characters ♪ ♫ # dict/post_dict.txt - Applied after translation (standardize output) # Fix common translation mistakes Mr\. -san Mrs\. -san Miss -chan # Standardize honorifics \bsenpai\b Senpai \bkouhai\b Kouhai ``` -------------------------------- ### Start Image Translation Process (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Initiates the translation process for a given image file. It checks if a translation is already in progress and either adds the new image to the queue or starts processing it immediately. This function manages the initial state and queuing of translation tasks. ```javascript startTranslation() { if (!this.file) return; // Clear any finished items from queue this.clearFinishedItems(); const currentFile = this.file; // Check if something is actually currently translating (has a real processing step status) const processingSteps = ['upload', 'pending', 'detection', 'ocr', 'mask-generation', 'inpainting', 'upscaling', 'translating', 'rendering']; const isCurrentlyTranslating = this.queuedImages.some(item => processingSteps.includes(item.status)); console.log('Currently translating:', isCurrentlyTranslating); console.log('Current queue statuses:', this.queuedImages.map(item => ({ id: item.id, status: item.status }))); if (isCurrentlyTranslating) { // Add to back of queue with 'queued' status const queuedImage = { id: Date.now() + Math.random(), file: currentFile, addedAt: new Date(), status: 'queued' // Explicitly set as queued }; this.queuedImages.push(queuedImage); this.file = null; // Clear current file console.log('Added image to queue with status:', queuedImage.status); } else { // Start translating immediately with 'processing' status const queuedImage = { id: Date.now() + Math.random(), file: currentFile, addedAt: new Date(), status: 'processing' // This one will be processing }; this.queuedImages.push(queuedImage); this.file = null; // Clear current file console.log('Starting translation with status:', queuedImage.status); // Start the translation process this.processTranslation(queuedImage); } } ``` -------------------------------- ### Add Multiple Files to Queue (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Adds an array of files to the translation queue, assigning a unique ID, timestamp, and initial 'queued' status. It then checks if any translation is in progress and starts processing the first queued item if the queue is idle. ```javascript addMultipleFilesToQueue(files) { console.log(`Adding ${files.length} files to queue`); // Clear any finished items from queue first this.clearFinishedItems(); files.forEach((file, index) => { const queuedImage = { id: Date.now() + Math.random() + index, file: file, addedAt: new Date(), status: 'queued' }; this.queuedImages.push(queuedImage); }); console.log(`Queue now has ${this.queuedImages.length} items`); // If nothing is currently processing, start the first one const processingSteps = ['upload', 'pending', 'detection', 'ocr', 'mask-generation', 'inpainting', 'upscaling', 'translating', 'rendering']; const isCurrentlyTranslating = this.queuedImages.some(item => processingSteps.includes(item.status)); if (!isCurrentlyTranslating && this.queuedImages.length > 0) { // Start processing the first queued item const firstQueuedIndex = this.queuedImages.findIndex(item => item.status === 'queued'); if (firstQueuedIndex !== -1) { this.queuedImages[firstQueuedIndex].status = 'processing'; this.processTranslation(this.queuedImages[firstQueuedIndex]); } } } ``` -------------------------------- ### Customize AI Translator Behavior with YAML Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Customizes AI translator behavior using a YAML configuration file for prompt engineering and model parameters. This file allows setting global defaults, system prompt templates, per-translator overrides, and few-shot examples. ```yaml # gpt_config.yaml - GPT/AI Translator Configuration # Global defaults temperature: 0.5 top_p: 1 verbose_logging: false # System prompt template chat_system_template: > You are an untrammelled professional translation engine. Please translate the text into colloquial, elegant and fluent {to_lang}, without referencing machine translations. You must only translate the story, never interpret it. If already in {to_lang} or looks like gibberish, output it as is. Translate to {to_lang}. # Per-translator overrides chatgpt: include_template: true gpt-4o-mini: temperature: 0.4 gpt-3.5-turbo: temperature: 0.3 gemini: temperature: 0.5 top_p: 0.95 ollama: deepseek-r1: rgx_capture: '.*\s*(.*)|(.*)' # Prompt template prepended to user messages prompt_template: 'Please help me to translate the following text from a manga to {to_lang}:' # Few-shot examples for each target language chat_sample: English: - "<|1|>Original Japanese text\n<|2|>More text" - "<|1|>Translated English text\n<|2|>More translation" Chinese (Simplified): - "<|1|>Original Japanese text" - "<|1|>Translated Chinese text" ``` -------------------------------- ### Get User-Friendly Step Name (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Translates internal step status strings into human-readable names for display. It uses a mapping object to provide user-friendly labels for various stages of the image processing pipeline. Returns the original step string if no mapping is found. ```javascript getStepName(step) { const stepNames = { 'upload': 'Uploading', 'pending': 'Queuing', 'detection': 'Detecting texts', 'ocr': 'Running OCR', 'mask-generation': 'Generating text mask', 'inpainting': 'Running inpainting', 'upscaling': 'Running upscaling', 'translating': 'Translating', 'rendering': 'Rendering translated texts', 'finished': 'Finished' }; return stepNames[step] || step; } ``` -------------------------------- ### Response Processing Logic (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/manual.html Processes the streaming response from the translation API. It decodes the data, handles different status codes (0 for data, 1 for step, 2 for error, 3 for queue, 4 for started), and updates the UI accordingly. It supports downloading text or byte data. ```javascript async function process(response, statusField, errorField, image) { if (response.ok) { const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let buffer = new Uint8Array(); while (true) { const { done, value } = await reader.read(); if (done) break; const newBuffer = new Uint8Array(buffer.length + value.length); newBuffer.set(buffer); newBuffer.set(value, buffer.length); buffer = newBuffer; while (buffer.length >= 5) { const dataSize = new DataView(buffer.buffer).getUint32(1, false); const totalSize = 5 + dataSize; if (buffer.length < totalSize) { break; } const statusCode = buffer[0]; const data = buffer.slice(5, totalSize); if(statusCode === 0) { if(image) { gdata = new Blob([data], { type: 'application/octet-stream' }); statusField.innerHTML = ''; } else { gdata = decoder.decode(data); statusField.innerHTML = ''; } } else if(statusCode === 1) { const parsed_data = decoder.decode(data); statusField.innerHTML = `translation step ${parsed_data}`; } else if(statusCode === 2) { statusField.innerHTML = decoder.decode(data); errorField.innerHTML = ""; } else if(statusCode === 3) { const parsed_data = decoder.decode(data); statusField.innerHTML = `in queue: ${parsed_data}`; } else if(statusCode === 4) { statusField.innerHTML = `started translation`; } buffer = buffer.slice(totalSize); } } } else { errorField.innerHTML = response.statusText; } } ``` -------------------------------- ### Configure Environment Variables Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Sets up environment variables for API keys and service endpoints in a .env file. This includes configurations for OpenAI, DeepL, DeepSeek, Groq, Google Gemini, and custom OpenAI-compatible endpoints. ```bash # .env file - Place in project root # OpenAI/ChatGPT Configuration OPENAI_API_KEY=sk-your-api-key-here OPENAI_MODEL=chatgpt-4o-latest OPENAI_API_BASE=https://api.openai.com/v1 OPENAI_HTTP_PROXY= OPENAI_GLOSSARY_PATH=./dict/mit_glossary.txt # DeepL Translation DEEPL_AUTH_KEY=your-deepl-key # DeepSeek DEEPSEEK_API_KEY=your-deepseek-key DEEPSEEK_API_BASE=https://api.deepseek.com DEEPSEEK_MODEL=deepseek-chat # Groq GROQ_API_KEY=your-groq-key GROQ_MODEL=mixtral-8x7b-32768 # Google Gemini GEMINI_API_KEY=your-gemini-key GEMINI_MODEL=gemini-1.5-flash-002 # Custom OpenAI-compatible endpoint (Ollama, etc.) CUSTOM_OPENAI_API_KEY=ollama CUSTOM_OPENAI_API_BASE=http://localhost:11434/v1 CUSTOM_OPENAI_MODEL=qwen2.5:7b ``` -------------------------------- ### Use Dictionaries via CLI Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Command-line interface usage for the manga translator, demonstrating how to specify input directories and apply pre- and post-translation dictionaries. The `--use-gpu` flag indicates GPU acceleration. ```bash # Use dictionaries via CLI python -m manga_translator local -i /path/to/manga \ --pre-dict ./dict/pre_dict.txt \ --post-dict ./dict/post_dict.txt \ --use-gpu ``` -------------------------------- ### Run CLI Translation via Docker Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Executes command-line interface (CLI) translation using Docker. This command mounts local input and output directories, enables GPU usage, and passes the OpenAI API key. ```bash # Run CLI translation via Docker docker run --rm \ -v $(pwd)/input:/app/input \ -v $(pwd)/output:/app/output \ --gpus all \ -e OPENAI_API_KEY="sk-xxx" \ zyddnys/manga-image-translator:main \ local -i /app/input -o /app/output --use-gpu ``` -------------------------------- ### Download File Functionality (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/manual.html Provides functions to download data as a file. `downloadFile` handles text data, while `download_bytes` handles binary data (like images). It dynamically creates links to trigger downloads. ```javascript var gdata = null; function downloadFile() { download("text.json", gdata) } function download(filename, text) { let element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } function download_bytes() { const url = URL.createObjectURL(gdata); const element = document.createElement('a'); element.setAttribute('href', url); element.setAttribute('download', "image.png"); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); URL.revokeObjectURL(url); } ``` -------------------------------- ### Handle Keyboard Navigation for Modal (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Manages keyboard input for image modal interactions. It supports closing the modal with 'Escape', navigating images with arrow keys, and toggling zoom with 'z'. Requires 'showImageModal', 'closeImageModal', 'previousImage', 'nextImage', and 'toggleZoom' functions to be defined. ```javascript handleKeydown(event) { if (!this.showImageModal) return; switch (event.key) { case 'Escape': this.closeImageModal(); break; case 'ArrowLeft': this.previousImage(); break; case 'ArrowRight': this.nextImage(); break; case 'z': case 'Z': this.toggleZoom(); break; } } ``` -------------------------------- ### Handle Middle Mouse Button Drag on Image (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Implements drag functionality for an image using the middle mouse button. It captures the drag start position and updates the image's translation based on mouse movement. Requires 'isDragging', 'dragStart', and 'dragStartTransform' properties to be managed. ```javascript onImageMouseDown(event) { if (event.button === 1) { // Middle mouse button event.preventDefault(); this.isDragging = true; this.dragStart = { x: event.clientX, y: event.clientY }; this.dragStartTransform = { ...this.imageTransform }; } }, onImageMouseMove(event) { if (this.isDragging && this.isImageZoomed) { const deltaX = event.clientX - this.dragStart.x; const deltaY = event.clientY - this.dragStart.y; this.imageTransform.translateX = this.dragStartTransform.translateX + deltaX; this.imageTransform.translateY = this.dragStartTransform.translateY + deltaY; } }, onImageMouseUp() { this.isDragging = false; } ``` -------------------------------- ### Run All Tests with Pytest Source: https://github.com/zyddnys/manga-image-translator/blob/main/test/README.md Executes all tests within the 'test/' directory. This command is the standard way to ensure the entire project's test suite passes. ```bash pytest test/ ``` -------------------------------- ### Utility Functions for File Formatting (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Provides functions to format file sizes into human-readable units (B, KB, MB, etc.) and to display upload progress. These utilities are essential for user feedback during file operations. ```javascript const BASE_URI = "./"; const acceptTypes = [ "image/png", "image/jpeg", "image/bmp", "image/webp", ]; function formatSize(bytes) { const k = 1024; const sizes = ["B", "KB", "MB", "GB", "TB"]; if (bytes === 0) return "0B"; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / k ** i).toFixed(2)}${sizes[i]}`; } function formatProgress(loaded, total) { return `${formatSize(loaded)}/${formatSize(total)}`; } ``` -------------------------------- ### View Docker Compose Logs Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Follows the logs of the manga-translator service running via Docker Compose. This command is useful for monitoring the application's activity and debugging issues. ```bash # Check logs docker-compose logs -f manga-translator ``` -------------------------------- ### Deploy Translator with Docker Compose Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Deploys the translator using Docker for containerized execution with GPU support. This Docker Compose file defines the service, image, ports, volumes, environment variables, and resource reservations for GPU usage. ```yaml # docker-compose.yml version: '3.8' services: manga-translator: image: zyddnys/manga-image-translator:main container_name: manga_translator ports: - "5003:5003" - "8000:8000" volumes: - ./result:/app/result - ./input:/app/input environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - DEEPL_AUTH_KEY=${DEEPL_AUTH_KEY} deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] command: > python server/main.py --verbose --start-instance --host=0.0.0.0 --port=5003 --use-gpu ``` -------------------------------- ### Sync Gallery with Results Directory Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Fetches the list of completed translation folders from the server and synchronizes them with the local gallery state. It ensures new results are added and persists the gallery to localStorage. ```javascript async syncGalleryWithResults() { try { const response = await fetch(`${BASE_URI}results/list`); if (response.ok) { const data = await response.json(); const folders = data.directories || []; for (const folder of folders) { const existingImage = this.finishedImages.find(img => img.result && img.result.includes(folder)); if (!existingImage) { const finalResponse = await fetch(`${BASE_URI}result/${folder}/final.png`); if (finalResponse.ok) { this.finishedImages.unshift({ id: Date.now(), originalName: folder, result: `${BASE_URI}result/${folder}/final.png` }); } } } } } catch (error) { console.warn('Failed to sync gallery:', error); } } ``` -------------------------------- ### Manage Image Processing Queue in Vue Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Handles the transition of images from 'queued' to 'processing' and 'finished' states. It includes logic for auto-triggering the next item in the queue and updating the UI state reactively. ```javascript processNextInQueue() { const nextItemIndex = this.queuedImages.findIndex(item => item.status === 'queued'); if (nextItemIndex !== -1) { const nextItem = this.queuedImages[nextItemIndex]; this.queuedImages[nextItemIndex] = { ...nextItem, status: 'processing' }; this.processTranslation(this.queuedImages[nextItemIndex]); } } ``` -------------------------------- ### Queue Management Functions (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Provides functions to clear the currently selected single file, clear all selected files, and add selected files to the translation queue. It also includes a function to add multiple files to the queue and initiate processing. ```javascript // Queue management clearFile() { this.file = null; }, clearSelectedFiles() { this.selectedFiles = []; }, addSelectedFilesToQueue() { if (this.selectedFiles.length > 0) { this.addMultipleFilesToQueue(this.selectedFiles); this.selectedFiles = []; } } ``` -------------------------------- ### POST /translate/batch/images Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Translates a batch of images provided as base64 strings and returns the result as a ZIP archive. ```APIDOC ## POST /translate/batch/images ### Description Translates multiple manga images in one request and returns a ZIP archive containing the translated files. ### Method POST ### Endpoint /translate/batch/images ### Request Body - **images** (array) - Required - List of base64 encoded image strings. - **config** (object) - Required - Translation configuration settings (translator, target_lang). - **batch_size** (integer) - Optional - Number of images to process in a single batch. ### Request Example { "images": ["data:image/png;base64,..."], "config": {"translator": {"translator": "sugoi", "target_lang": "ENG"}}, "batch_size": 2 } ### Response #### Success Response (200) - **file** (binary) - ZIP archive containing translated images. #### Response Example Binary ZIP data ``` -------------------------------- ### CLI Batch Translation with Manga Image Translator Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Translate local images or folders using the command-line interface. Supports various options for specifying input, output, GPU acceleration, and translation models. ```bash # Basic translation of a single image (Japanese to English) python -m manga_translator local -v -i /path/to/manga_page.jpg # Translate entire folder with GPU acceleration python -m manga_translator local -v -i /path/to/manga_folder --use-gpu # Specify target language (Chinese Simplified) python -m manga_translator local -v -i /path/to/image.png \ --translator sugoi \ --target-lang CHS # Full example with multiple options python -m manga_translator local \ -v \ -i /path/to/images \ --use-gpu \ --translator chatgpt \ --target-lang ENG \ --detector ctd \ --ocr 48px \ --inpainter lama_large \ --font-path /path/to/custom_font.ttf \ --format png \ --overwrite # Output is saved to: /path/to/images-translated/ ``` -------------------------------- ### POST /translate/with-form/image Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Uploads an image file using multipart form data and returns the translated image file directly. ```APIDOC ## POST /translate/with-form/image ### Description Uploads an image file and receives the processed, translated image as a binary response. ### Method POST ### Endpoint /translate/with-form/image ### Parameters #### Request Body - **image** (file) - Required - The image file to translate. - **config** (string) - Optional - JSON string containing translation configurations. ### Request Example curl -X POST "http://127.0.0.1:8000/translate/with-form/image" \ -F "image=@manga_page.png" \ -F 'config={"translator":{"translator":"chatgpt","target_lang":"ENG"}}' \ --output translated_page.png ### Response #### Success Response (200) - **image/png** (binary) - The translated image file. ``` -------------------------------- ### Manga Image Translator Application Logic (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html The core logic for the Manga Image Translator application, built with Petite-Vue. It handles file uploads, settings persistence, translation queue management, gallery display, and real-time synchronization with results. It also includes extensive configuration options for translation and image processing. ```javascript PetiteVue.createApp({ onmounted() { window.addEventListener("paste", this.onpaste); this.loadSettings(); this.loadFinishedImages(); // Sync gallery with results folder on page load setTimeout(() => { this.syncGalleryWithResults(); }, 1000); // Periodically sync gallery with results folder setInterval(() => { this.syncGalleryWithResults(); }, 30000); // Sync every 30 seconds // Add keyboard event listeners for modal navigation window.addEventListener('keydown', this.handleKeydown); }, file: null, get fileUri() { return this.file ? URL.createObjectURL(this.file) : null; }, // New features: Queue and Gallery queuedImages: [], finishedImages: [], showGallery: false, selectedFiles: [], // Store multiple selected files before adding to queue // Gallery modal selectedImage: null, showImageModal: false, isImageZoomed: false, imageTransform: { scale: 1, translateX: 0, translateY: 0, }, isDragging: false, // Step tracking for progress translationSteps: [ 'upload', 'pending', 'detection', 'ocr', 'mask-generation', 'inpainting', 'upscaling', 'translating', 'rendering', 'finished', ], // Map actual server status to step numbers for better progress tracking statusToStep: { 'upload': 1, 'pending': 2, 'detection': 3, 'ocr': 4, 'mask-generation': 5, 'inpainting': 6, 'upscaling': 7, 'translating': 8, 'rendering': 9, 'finished': 10, }, detectionResolution: "1536", textDetector: "default", renderTextDirection: "auto", translator: "youdao", validTranslators: [ "youdao", "baidu", "deepl", "papago", "caiyun", "sakura", "offline", "openai", "deepseek", "groq", "gemini", "custom_openai", "nllb", "nllb_big", "m2m100", "m2m100_big", "mbart50", "qwen2", "qwen2_big", "none", "original", ], getTranslatorName(key) { if (key === "none") return "No Text"; return key ? key[0].toUpperCase() + key.slice(1) : ""; }, targetLanguage: "CHS", inpaintingSize: "2048", customUnclipRatio: 2.3, customBoxThreshold: 0.7, maskDilationOffset: 30, inpainter: "lama_large", uploadController: null, // Settings change handlers for auto-saving onSettingChange() { this.saveSettings(); }, // Settings persistence loadSettings() { try { const saved = localStorage.getItem('manga-translator-settings'); if (saved) { const settings = JSON.parse(saved); if (settings.detectionResolution) this.detectionResolution = settings.detectionResolution; if (settings.textDetector) this.textDetector = settings.textDetector; if (settings.renderTextDirection) this.renderTextDirection = settings.renderTextDirection; if (settings.translator) this.translator = settings.translator; if (settings.targetLanguage) this.targetLanguage = settings.targetLanguage; if (settings.inpaintingSize) this.inpaintingSize = settings.inpaintingSize; if (settings.customUnclipRatio) this.customUnclipRatio = settings.customUnclipRatio; if (settings.customBoxThreshold) this.customBoxThreshold = settings.customBoxThreshold; if (settings.maskDilationOffset) this.maskDilationOffset = settings.maskDilationOffset; if (settings.inpainter) this.inpainter = settings.inpainter; } } catch (error) { console.warn('Failed to load settings:', error); } }, saveSettings() { try { const settings = { detectionResolution: this.detectionResolution, textDetector: this.textDetector, renderTextDirection: this.renderTextDirection, translator: this.translator, targetLanguage: this.targetLanguage, inpaintingSize: this.inpaintingSize, customUnclipRatio: this.customUnclipRatio, customBoxThreshold: this.customBoxThreshold, maskDilationOffset: this.maskDilationOffset, inpainter: this.inpainter, }; localStorage.setItem('manga-translator-settings', JSON.stringify(settings)); } catch (error) { console.warn('Failed to save settings:', error); } }, ondrop(e) { const files = Array.from(e.dataTransfer?.files || []); const validFiles = files.filter(file => acceptTypes.includes(file.type)); if (validFiles.length === 1 && !this.file && this.selectedFiles.length === 0) { // Single file and no current file or selected files - maintain existing behavior this.file = validFiles[0]; this.selectedFiles = []; // Clear any selected files } else if (validFiles.length > 0) { // Multiple files o ``` -------------------------------- ### Configure Translation Settings with JSON Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Defines comprehensive translation settings in a JSON configuration file. This file allows customization of rendering, upscaling, translation, detection, colorization, inpainting, and OCR parameters. ```json { "filter_text": null, "render": { "renderer": "default", "alignment": "auto", "disable_font_border": false, "font_size_offset": 0, "font_size_minimum": -1, "direction": "auto", "uppercase": false, "lowercase": false, "gimp_font": "Sans-serif", "no_hyphenation": false, "font_color": null, "line_spacing": null, "font_size": null, "rtl": true }, "upscale": { "upscaler": "esrgan", "revert_upscaling": false, "upscale_ratio": null }, "translator": { "translator": "chatgpt", "target_lang": "ENG", "no_text_lang_skip": false, "skip_lang": "ENG", "gpt_config": "gpt_config.yaml", "translator_chain": null, "selective_translation": null, "enable_post_translation_check": true, "post_check_max_retry_attempts": 3 }, "detector": { "detector": "default", "detection_size": 2048, "text_threshold": 0.5, "det_rotate": false, "det_auto_rotate": false, "det_invert": false, "det_gamma_correct": false, "box_threshold": 0.7, "unclip_ratio": 2.3 }, "colorizer": { "colorization_size": 576, "denoise_sigma": 30, "colorizer": "none" }, "inpainter": { "inpainter": "lama_large", "inpainting_size": 2048, "inpainting_precision": "bf16" }, "ocr": { "use_mocr_merge": false, "ocr": "48px", "min_text_length": 0, "ignore_bubble": 0 }, "kernel_size": 3, "mask_dilation_offset": 20 } ``` -------------------------------- ### Navigate Between Images (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Provides functions to move to the next or previous image in a list. When switching images, it resets the zoom and translation state. Assumes 'finishedImages' and 'selectedImage' are managed, and 'isImageZoomed' and 'imageTransform' are available for reset. ```javascript nextImage() { if (this.selectedImage) { const currentIndex = this.finishedImages.findIndex(img => img.id === this.selectedImage.id); if (currentIndex < this.finishedImages.length - 1) { this.selectedImage = this.finishedImages[currentIndex + 1]; // Reset transform when switching images this.isImageZoomed = false; this.imageTransform = { scale: 1, translateX: 0, translateY: 0 }; } } }, previousImage() { if (this.selectedImage) { const currentIndex = this.finishedImages.findIndex(img => img.id === this.selectedImage.id); if (currentIndex > 0) { this.selectedImage = this.finishedImages[currentIndex - 1]; // Reset transform when switching images this.isImageZoomed = false; this.imageTransform = { scale: 1, translateX: 0, translateY: 0 }; } } } ``` -------------------------------- ### File Selection Dialogs (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Dynamically creates and triggers hidden file input elements to allow users to select multiple files or an entire folder of images. The selected valid image files are then stored in 'this.selectedFiles'. ```javascript selectMultipleFiles() { // Create a temporary file input for multiple file selection const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/png,image/jpeg,image/bmp,image/webp'; input.multiple = true; input.onchange = (e) => { const files = Array.from(e.target.files || []); const validFiles = files.filter(file => acceptTypes.includes(file.type)); if (validFiles.length > 0) { this.selectedFiles = validFiles; this.file = null; // Clear single file } }; input.click(); }, selectFolder() { // Create a temporary file input for folder selection const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/png,image/jpeg,image/bmp,image/webp'; input.webkitdirectory = true; input.multiple = true; input.onchange = (e) => { const files = Array.from(e.target.files || []); const validFiles = files.filter(file => acceptTypes.includes(file.type)); if (validFiles.length > 0) { this.selectedFiles = validFiles; this.file = null; // Clear single file } }; input.click(); } ``` -------------------------------- ### Calculate Step Progress for Queued Image (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Calculates the progress percentage for a queued image based on its status. It maps specific status strings to numerical steps and computes the overall progress. Handles 'queued', 'finished', 'error', and 'processing' statuses, with fallback for unknown statuses. Relies on a 'stepMap' and 'totalSteps' for calculation. ```javascript getStepProgress(queuedImage) { console.log('Calculating progress for status:', queuedImage.status); if (!queuedImage.status || queuedImage.status === 'queued') { return { percentage: 0 }; } // Map status to step number for progress calculation const stepMap = { 'upload': 1, 'pending': 2, 'detection': 3, 'ocr': 4, 'mask-generation': 5, 'inpainting': 6, 'upscaling': 7, 'translating': 8, 'rendering': 9, 'finished': 10 }; const currentStep = stepMap[queuedImage.status]; console.log('Status maps to step:', currentStep); if (currentStep === undefined) { // If status is not in our map, estimate based on known steps if (queuedImage.status === 'error') { return { percentage: 0 }; } if (queuedImage.status === 'processing') { // For 'processing' status, show 0% until we get actual step updates return { percentage: 0 }; } // For unknown status, assume it's in the middle return { percentage: 50 }; } const totalSteps = 10; const percentage = Math.round(((currentStep - 1) / (totalSteps - 1)) * 100); console.log('Progress result:', { percentage }); return { percentage: percentage }; } ``` -------------------------------- ### Image Upload and Translation Logic (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/manual.html Handles the core logic for uploading an image file and sending it for translation. It manages UI element states, constructs form data, and initiates the fetch request. It also includes error handling and status updates. ```javascript async function uploadAndTranslate() { const errorField = document.getElementById('error'); const statusField = document.getElementById('status'); let submitButton = document.getElementById("submit-button") const fileInput = document.getElementById('fileInput'); const generateImage = document.getElementById('generate-image'); const configField = document.getElementById('config-json'); submitButton.classList.add("hidden"); fileInput.classList.add("hidden"); generateImage.classList.add("hidden"); configField.classList.add("hidden"); statusField.innerHTML = ''; errorField.innerHTML = ''; const file = fileInput.files[0]; if (!file) { alert('Please select an image file.'); return; } statusField.innerHTML = 'Uploading...'; const formData = new FormData(); formData.append('image', file); const text = configField.innerText; if (text.length > 2) { formData.append('config', text) } try { const response = await fetch( generateImage.checked ? '/translate/with-form/image/stream' : '/translate/with-form/json/stream', { method: 'POST', body: formData, /*headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image: base64Image, config: { translator: { target_lang: "ENG" } } }) */ }); await process(response, statusField, errorField, generateImage.checked) } catch (error) { errorField.innerHTML = response.statusText; } finally { submitButton.classList.remove("hidden"); fileInput.classList.remove("hidden"); generateImage.classList.remove("hidden"); configField.classList.remove("hidden"); } } ``` -------------------------------- ### Load and Add Finished Images (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Handles loading previously translated images from local storage and adding new translated images to this collection. It includes error handling for local storage access and stores relevant metadata for each finished image. ```javascript loadFinishedImages() { try { const saved = localStorage.getItem('manga-translator-finished-images'); if (saved) { this.finishedImages = JSON.parse(saved); } } catch (error) { console.warn('Failed to load finished images:', error); } }, addToFinishedImages(imageData) { const finishedImage = { id: Date.now() + Math.random(), originalName: imageData.name || 'Unknown', result: imageData.result, finishedAt: new Date(), settings: { detectionResolution: this.detectionResolution, textDetector: this.textDetector, renderTextDirection: this.renderTextDirection, translator: this.translator, targetLanguage: this.targetLanguage, inpaintingSize: this.inpaintingSize, customUnc } }; this.finishedImages.push(finishedImage); // Optionally save to local storage here } ``` -------------------------------- ### REST API: Batch Translation with Manga Image Translator Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Perform batch translation of multiple images in a single request using the REST API. Specify a list of image URLs and configure translation settings and batch size. ```bash # Batch translate multiple images curl -X POST "http://127.0.0.1:8000/translate/batch/json" \ -H "Content-Type: application/json" \ -d '{ "images": [ "https://example.com/page1.jpg", "https://example.com/page2.jpg", "https://example.com/page3.jpg" ], "config": { "translator": {"translator": "chatgpt", "target_lang": "ENG"} }, "batch_size": 4 }' ``` -------------------------------- ### POST /translate/batch/json Source: https://context7.com/zyddnys/manga-image-translator/llms.txt Translates multiple images in a single request for improved throughput. ```APIDOC ## POST /translate/batch/json ### Description Processes a list of image URLs in a single batch request. ### Method POST ### Endpoint /translate/batch/json ### Request Body - **images** (array) - Required - List of image URLs. - **config** (object) - Optional - Translation settings. - **batch_size** (integer) - Optional - Number of images to process concurrently. ### Request Example { "images": ["https://example.com/page1.jpg", "https://example.com/page2.jpg"], "config": {"translator": {"translator": "chatgpt", "target_lang": "ENG"}}, "batch_size": 4 } ``` -------------------------------- ### Manage Image Lifecycle and Queue Processing Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Handles the post-processing of translated images by updating the local gallery and triggering queue automation. It includes methods to clear finished items and automatically process the next item in the queue after specified delays. ```javascript this.addToFinishedImages({ name: item.file.name, result: `${BASE_URI}result/${this.currentFolder || 'test'}/final.png` }); setTimeout(() => { this.clearFinishedItems(); }, 2000); setTimeout(() => { this.processNextInQueue(); }, 1000); ``` -------------------------------- ### Handle Image Modal Zoom Interaction Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Provides functionality to toggle zoom levels on images within the modal. It calculates the transform origin based on the user's click coordinates for a localized zoom effect. ```javascript toggleZoom(event) { if (this.isImageZoomed) { this.isImageZoomed = false; this.imageTransform = { scale: 1, translateX: 0, translateY: 0 }; } else { this.isImageZoomed = true; this.imageTransform.scale = 2; if (event) { const rect = event.target.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; event.target.style.transformOrigin = `${x}px ${y}px`; } } } ``` -------------------------------- ### Handle File Input Changes (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Processes file inputs from user selections, filtering for accepted image types. It distinguishes between single file uploads (setting 'this.file') and multiple file uploads (setting 'this.selectedFiles'). ```javascript onfilechange(e) { const files = Array.from(e.target.files || []); const validFiles = files.filter(file => acceptTypes.includes(file.type)); if (validFiles.length === 1) { // Single file - maintain existing behavior this.file = validFiles[0]; this.selectedFiles = []; // Clear any selected files } else if (validFiles.length > 1) { // Multiple files - store them for preview, don't add to queue yet this.selectedFiles = validFiles; this.file = null; // Clear single file // Clear the file input e.target.value = ''; } } ``` -------------------------------- ### Skip Current Translation and Move to Next (JavaScript) Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Allows skipping the current translation process. It aborts any ongoing upload, marks the current item as 'error' with a 'Skipped by user' message, and then clears finished items and proceeds to the next item in the queue. Requires 'uploadController', 'clearFinishedItems', and 'processNextInQueue' to be available. ```javascript skipCurrentTranslation() { console.log('Skip current translation called'); console.log('Current queued images:', this.queuedImages); const processingItemIndex = this.queuedImages.findIndex(item => item.status === 'processing'); console.log('Processing item index:', processingItemIndex); if (processingItemIndex !== -1) { const processingItem = this.queuedImages[processingItemIndex]; console.log('Found processing item:', processingItem); // Abort current translation this.uploadController?.abort(); console.log('Aborted upload controller'); // Mark current item as skipped/error this.queuedImages[processingItemIndex] = { ...processingItem, status: 'error', error: 'Skipped by user' }; console.log('Marked item as skipped'); // Clear finished/error items and move to next setTimeout(() => { this.clearFinishedItems(); this.processNextInQueue(); }, 1000); } else { } } ``` -------------------------------- ### Reset Application State Source: https://github.com/zyddnys/manga-image-translator/blob/main/server/index.html Resets the application state variables to their initial values and aborts any active upload controllers. This is used to clear the current session data. ```javascript clear() { this.uploadController?.abort(); this.file = null; this.result = null; this.currentFolder = null; this.finalPngDisplayed = false; this.useFileResult = true; this.status = null; this.progress = null; this.queuePos = null; this.errorMessage = null; } ```