From e749b3bc88d2fd5253ef4558ca0861157b1ae742 Mon Sep 17 00:00:00 2001 From: remsky Date: Wed, 1 Jan 2025 21:50:00 -0700 Subject: [PATCH] Add Gradio web interface + tests --- .coveragerc | 4 +- CHANGELOG.md | 4 + README.md | 131 +++++++++++++++------- docker-compose.yml | 22 ++-- pytest.ini | 4 +- ui/GradioScreenShot.png | Bin 0 -> 115763 bytes ui/lib/api.py | 11 +- ui/lib/components/__init__.py | 2 +- ui/lib/components/input.py | 24 +++- ui/lib/components/model.py | 14 +-- ui/lib/components/output.py | 5 +- ui/lib/files.py | 24 ++++ ui/lib/handlers.py | 201 ++++++++++++++++++++++++++-------- ui/lib/interface.py | 56 ++++++++-- ui/tests/conftest.py | 9 ++ ui/tests/test_api.py | 129 ++++++++++++++++++++++ ui/tests/test_components.py | 116 ++++++++++++++++++++ ui/tests/test_files.py | 195 +++++++++++++++++++++++++++++++++ ui/tests/test_handlers.py | 4 + ui/tests/test_input.py | 74 +++++++++++++ ui/tests/test_interface.py | 139 +++++++++++++++++++++++ 21 files changed, 1048 insertions(+), 120 deletions(-) create mode 100644 ui/GradioScreenShot.png create mode 100644 ui/tests/conftest.py create mode 100644 ui/tests/test_api.py create mode 100644 ui/tests/test_components.py create mode 100644 ui/tests/test_files.py create mode 100644 ui/tests/test_handlers.py create mode 100644 ui/tests/test_input.py create mode 100644 ui/tests/test_interface.py diff --git a/.coveragerc b/.coveragerc index 4072f19..dab8655 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,7 @@ [run] -source = api +source = + api + ui omit = Kokoro-82M/* MagicMock/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 36715cd..44c98bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Notable changes to this project will be documented in this file. ## 2024-01-09 +### Added +- Gradio Web Interface: + - Added simple web UI utility for audio generation from input or txt file + ### Modified #### Configuration Changes - Updated Docker configurations: diff --git a/README.md b/README.md index a626cc0..392ab68 100644 --- a/README.md +++ b/README.md @@ -3,42 +3,55 @@

# Kokoro TTS API -[![Tests](https://img.shields.io/badge/tests-37%20passed-darkgreen)]() -[![Coverage](https://img.shields.io/badge/coverage-81%25-darkgreen)]() +[![Tests](https://img.shields.io/badge/tests-81%20passed-darkgreen)]() +[![Coverage](https://img.shields.io/badge/coverage-76%25-darkgreen)]() [![Tested at Model Commit](https://img.shields.io/badge/last--tested--model--commit-a67f113-blue)](https://huggingface.co/hexgrad/Kokoro-82M/tree/c3b0d86e2a980e027ef71c28819ea02e351c2667) -FastAPI wrapper for [Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M) text-to-speech model, providing an OpenAI-compatible endpoint with: +Dockerized FastAPI wrapper for [Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M) text-to-speech model +- OpenAI-compatible Speech endpoint, with voice combination functionality - NVIDIA GPU accelerated inference (or CPU) option +- very fast generation time (~35x real time factor) - automatic chunking/stitching for long texts -- very fast generation time (~35-49x RTF) +- simple audio generation web ui utility -## Quick Start +
+OpenAI-Compatible Speech Endpoint + +The service can be accessed through either the API endpoints or the Gradio web interface. 1. Install prerequisites: - - Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) - - Install [Git](https://git-scm.com/downloads) (or download and extract zip) + - Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) + [Git](https://git-scm.com/downloads) + - Clone and start the service: + ```bash + git clone https://github.com/remsky/Kokoro-FastAPI.git + cd Kokoro-FastAPI + docker compose up --build + ``` +2. Run locally as an OpenAI-Compatible Speech Endpoint + ```python + from openai import OpenAI + client = OpenAI( + base_url="http://localhost:8880", + api_key="not-needed" + ) -2. Clone and start the service: -```bash -# Clone repository -git clone https://github.com/remsky/Kokoro-FastAPI.git -cd Kokoro-FastAPI + response = client.audio.speech.create( + model="kokoro", + voice="af_bella", + input="Hello world!", + response_format="mp3" + ) + response.stream_to_file("output.mp3") + ``` -# For GPU acceleration (requires NVIDIA GPU): -docker compose up --build + or visit http://localhost:7860 +

+ Voice Analysis Comparison +

+
+
+OpenAI-Compatible Speech Endpoint -# For CPU-only deployment (~10x slower, but doesn't require an NVIDIA GPU): -docker compose -f docker-compose.cpu.yml up --build -``` -Quick tests (run from another terminal): -```bash -# Test OpenAI Compatibility -python examples/test_openai_tts.py -# Test all available voices -python examples/test_all_voices.py -``` - -## OpenAI-Compatible API ```python # Using OpenAI's Python library from openai import OpenAI @@ -77,16 +90,26 @@ with open("output.mp3", "wb") as f: f.write(response.content) ``` -## Voice Combination +Quick tests (run from another terminal): +```bash +python examples/test_openai_tts.py # Test OpenAI Compatibility +python examples/test_all_voices.py # Test all available voices +``` +
+ +
+Voice Combination Combine voices and generate audio: ```python import requests +response = requests.get("http://localhost:8880/v1/audio/voices") +voices = response.json()["voices"] -# Create combined voice (saved locally on server) +# Create combined voice (saves locally on server) response = requests.post( "http://localhost:8880/v1/audio/voices/combine", - json=["af_bella", "af_sarah"] + json=[voices[0], voices[1]] ) combined_voice = response.json()["voice"] @@ -100,8 +123,27 @@ response = requests.post( } ) ``` +

+ Voice Analysis Comparison +

+
-## Performance Benchmarks +
+Gradio Web Utility + +Access the interactive web UI at http://localhost:7860 after starting the service. Features include: +- Voice/format/speed selection +- Audio playback and download +- Text file or direct input + +If you only want the API, just comment out everything in the docker-compose.yml under and including `gradio-ui` + +Currently, voices created via the API are accessible here, but voice combination/creation has not yet been added +
+ + +
+Performance Benchmarks Benchmarking was performed on generation via the local API using text lengths up to feature-length books (~1.5 hours output), measuring processing time and realtime factor. Tests were run on: - Windows 11 Home w/ WSL2 @@ -119,10 +161,22 @@ Benchmarking was performed on generation via the local API using text lengths up Key Performance Metrics: - Realtime Factor: Ranges between 35-49x (generation time to output audio length) - Average Processing Rate: 137.67 tokens/second (cl100k_base) +
+
+GPU Vs. CPU -## Features +```bash +# GPU: Requires NVIDIA GPU with CUDA 12.1 support +docker compose up --build -- OpenAI-compatible API endpoints +# CPU: ~10x slower than GPU inference +docker compose -f docker-compose.cpu.yml up --build +``` +
+
+Features + +- OpenAI-compatible API endpoints (with optional Gradio Web UI) - GPU-accelerated inference (if desired) - Multiple audio formats: mp3, wav, opus, flac, (aac & pcm not implemented) - Natural Boundary Detection: @@ -131,19 +185,21 @@ Key Performance Metrics: - Averages model weights of any existing voicepacks - Saves generated voicepacks for future use -

- Voice Analysis Comparison -

+ *Note: CPU Inference is currently a very basic implementation, and not heavily tested* +
-## Model +
+Model This API uses the [Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M) model from HuggingFace. Visit the model page for more details about training, architecture, and capabilities. I have no affiliation with any of their work, and produced this wrapper for ease of use and personal projects. +
-## License +
+License This project is licensed under the Apache License 2.0 - see below for details: @@ -152,3 +208,4 @@ This project is licensed under the Apache License 2.0 - see below for details: - The inference code adapted from StyleTTS2 is MIT licensed The full Apache 2.0 license text can be found at: https://www.apache.org/licenses/LICENSE-2.0 +
diff --git a/docker-compose.yml b/docker-compose.yml index 565d158..2722208 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,14 +46,14 @@ services: model-fetcher: condition: service_healthy - # # Gradio UI service - # gradio-ui: - # build: - # context: ./ui - # ports: - # - "7860:7860" - # volumes: - # - ./ui/data:/app/ui/data - # - ./ui/app.py:/app/app.py # Mount app.py for hot reload - # environment: - # - GRADIO_WATCH=True # Enable hot reloading + # Gradio UI service [Comment out everything below if you don't need it] + gradio-ui: + build: + context: ./ui + ports: + - "7860:7860" + volumes: + - ./ui/data:/app/ui/data + - ./ui/app.py:/app/app.py # Mount app.py for hot reload + environment: + - GRADIO_WATCH=True # Enable hot reloading diff --git a/pytest.ini b/pytest.ini index 3bcd461..47be4b5 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,5 +1,5 @@ [pytest] -testpaths = api/tests +testpaths = api/tests ui/tests python_files = test_*.py -addopts = -v --tb=short --cov=api --cov-report=term-missing --cov-config=.coveragerc +addopts = -v --tb=short --cov=api --cov=ui --cov-report=term-missing --cov-config=.coveragerc pythonpath = . diff --git a/ui/GradioScreenShot.png b/ui/GradioScreenShot.png new file mode 100644 index 0000000000000000000000000000000000000000..77af6b39b545310bc72d129f3d01b273de700725 GIT binary patch literal 115763 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°B3;lk7L@_x+$mh~P3n34banN744nrTK8~7~x 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 I-*t-kA0dL+hyVZp literal 0 HcmV?d00001 diff --git a/ui/lib/api.py b/ui/lib/api.py index 20e8b1d..a9c6a19 100644 --- a/ui/lib/api.py +++ b/ui/lib/api.py @@ -7,7 +7,11 @@ from .config import API_URL, OUTPUTS_DIR def check_api_status() -> Tuple[bool, List[str]]: """Check TTS service status and get available voices.""" try: - response = requests.get(f"{API_URL}/v1/audio/voices", timeout=5) + # Use a longer timeout during startup + response = requests.get( + f"{API_URL}/v1/audio/voices", + timeout=30 # Increased timeout for initial startup period + ) response.raise_for_status() voices = response.json().get("voices", []) if voices: @@ -15,7 +19,10 @@ def check_api_status() -> Tuple[bool, List[str]]: print("No voices found in response") return False, [] except requests.exceptions.Timeout: - print("API request timed out") + print("API request timed out (waiting for service startup)") + return False, [] + except requests.exceptions.ConnectionError as e: + print(f"Connection error (service may be starting up): {str(e)}") return False, [] except requests.exceptions.RequestException as e: print(f"API request failed: {str(e)}") diff --git a/ui/lib/components/__init__.py b/ui/lib/components/__init__.py index 637ee14..0d66be3 100644 --- a/ui/lib/components/__init__.py +++ b/ui/lib/components/__init__.py @@ -2,4 +2,4 @@ from .input import create_input_column from .model import create_model_column from .output import create_output_column -__all__ = ['create_input_column', 'create_model_column', 'create_output_column'] +__all__ = ["create_input_column", "create_model_column", "create_output_column"] diff --git a/ui/lib/components/input.py b/ui/lib/components/input.py index a80ecc9..2644060 100644 --- a/ui/lib/components/input.py +++ b/ui/lib/components/input.py @@ -6,6 +6,8 @@ def create_input_column() -> Tuple[gr.Column, dict]: """Create the input column with text input and file handling.""" with gr.Column(scale=1) as col: with gr.Tabs() as tabs: + # Set first tab as selected by default + tabs.selected = 0 # Direct Input Tab with gr.TabItem("Direct Input"): text_input = gr.Textbox( @@ -13,6 +15,11 @@ def create_input_column() -> Tuple[gr.Column, dict]: placeholder="Enter text here...", lines=4 ) + text_submit = gr.Button( + "Generate Speech", + variant="primary", + size="lg" + ) # File Input Tab with gr.TabItem("From File"): @@ -34,13 +41,28 @@ def create_input_column() -> Tuple[gr.Column, dict]: interactive=False, lines=4 ) + + with gr.Row(): + file_submit = gr.Button( + "Generate Speech", + variant="primary", + size="lg" + ) + clear_files = gr.Button( + "Clear Files", + variant="secondary", + size="lg" + ) components = { "tabs": tabs, "text_input": text_input, "file_select": input_files_list, "file_upload": file_upload, - "file_preview": file_preview + "file_preview": file_preview, + "text_submit": text_submit, + "file_submit": file_submit, + "clear_files": clear_files } return col, components diff --git a/ui/lib/components/model.py b/ui/lib/components/model.py index 41bcbfc..3b7ae96 100644 --- a/ui/lib/components/model.py +++ b/ui/lib/components/model.py @@ -10,10 +10,9 @@ def create_model_column(voice_ids: Optional[list] = None) -> Tuple[gr.Column, di with gr.Column(scale=1) as col: gr.Markdown("### Model Settings") - # Status button with embedded status - is_available, _ = api.check_api_status() + # Status button starts in waiting state status_btn = gr.Button( - f"Checking TTS Service: {'Available' if is_available else 'Not Yet Available'}", + "⌛ TTS Service: Waiting for Service...", variant="secondary" ) @@ -35,19 +34,12 @@ def create_model_column(voice_ids: Optional[list] = None) -> Tuple[gr.Column, di step=0.1, label="Speed" ) - - submit_btn = gr.Button( - "Generate Speech", - variant="primary", - size="lg" - ) components = { "status_btn": status_btn, "voice": voice_input, "format": format_input, - "speed": speed_input, - "submit": submit_btn + "speed": speed_input } return col, components diff --git a/ui/lib/components/output.py b/ui/lib/components/output.py index ff951fd..8ef4640 100644 --- a/ui/lib/components/output.py +++ b/ui/lib/components/output.py @@ -26,12 +26,15 @@ def create_output_column() -> Tuple[gr.Column, dict]: type="filepath", visible=False ) + + clear_outputs = gr.Button("⚠️ Delete All Previously Generated Output Audio 🗑️", size="sm", variant="secondary") components = { "audio_output": audio_output, "output_files": output_files, "play_btn": play_btn, - "selected_audio": selected_audio + "selected_audio": selected_audio, + "clear_outputs": clear_outputs } return col, components diff --git a/ui/lib/files.py b/ui/lib/files.py index 66d44ce..98867f3 100644 --- a/ui/lib/files.py +++ b/ui/lib/files.py @@ -56,6 +56,30 @@ def save_text(text: str, filename: Optional[str] = None) -> Optional[str]: print(f"Error saving file: {e}") return None +def delete_all_input_files() -> bool: + """Delete all files from the inputs directory. Returns True if successful.""" + try: + for filename in os.listdir(INPUTS_DIR): + if filename.endswith('.txt'): + file_path = os.path.join(INPUTS_DIR, filename) + os.remove(file_path) + return True + except Exception as e: + print(f"Error deleting input files: {e}") + return False + +def delete_all_output_files() -> bool: + """Delete all audio files from the outputs directory. Returns True if successful.""" + try: + for filename in os.listdir(OUTPUTS_DIR): + if any(filename.endswith(ext) for ext in AUDIO_FORMATS): + file_path = os.path.join(OUTPUTS_DIR, filename) + os.remove(file_path) + return True + except Exception as e: + print(f"Error deleting output files: {e}") + return False + def process_uploaded_file(file_path: str) -> bool: """Save uploaded file to inputs directory. Returns True if successful.""" if not file_path: diff --git a/ui/lib/handlers.py b/ui/lib/handlers.py index bcc15d7..94c9574 100644 --- a/ui/lib/handlers.py +++ b/ui/lib/handlers.py @@ -7,19 +7,40 @@ def setup_event_handlers(components: dict): """Set up all event handlers for the UI components.""" def refresh_status(): - is_available, voices = api.check_api_status() - status = "Available" if is_available else "Unavailable" - btn_text = f"🔄 TTS Service: {status}" - - if is_available and voices: - return { - components["model"]["status_btn"]: gr.update(value=btn_text), - components["model"]["voice"]: gr.update(choices=voices, value=voices[0] if voices else None) - } - return { - components["model"]["status_btn"]: gr.update(value=btn_text), - components["model"]["voice"]: gr.update(choices=[], value=None) - } + try: + is_available, voices = api.check_api_status() + status = "Available" if is_available else "Waiting for Service..." + + if is_available and voices: + # Preserve current voice selection if it exists and is still valid + current_voice = components["model"]["voice"].value + default_voice = current_voice if current_voice in voices else voices[0] + return [ + gr.update( + value=f"🔄 TTS Service: {status}", + interactive=True, + variant="secondary" + ), + gr.update(choices=voices, value=default_voice) + ] + return [ + gr.update( + value=f"⌛ TTS Service: {status}", + interactive=True, + variant="secondary" + ), + gr.update(choices=[], value=None) + ] + except Exception as e: + print(f"Error in refresh status: {str(e)}") + return [ + gr.update( + value="❌ TTS Service: Connection Error", + interactive=True, + variant="secondary" + ), + gr.update(choices=[], value=None) + ] def handle_file_select(filename): if filename: @@ -56,45 +77,95 @@ def setup_event_handlers(components: dict): return gr.update(choices=files.list_input_files()) - def generate_speech(text, selected_file, voice, format, speed): + def generate_from_text(text, voice, format, speed): + """Generate speech from direct text input""" is_available, _ = api.check_api_status() if not is_available: gr.Warning("TTS Service is currently unavailable") - return { - components["output"]["audio_output"]: None, - components["output"]["output_files"]: gr.update(choices=files.list_output_files()) - } - - # Use text input if provided, otherwise use file content - if text and text.strip(): - files.save_text(text) - final_text = text - elif selected_file: - final_text = files.read_text_file(selected_file) - else: - gr.Warning("Please enter text or select a file") - return { - components["output"]["audio_output"]: None, - components["output"]["output_files"]: gr.update(choices=files.list_output_files()) - } - - result = api.text_to_speech(final_text, voice, format, speed) + return [ + None, + gr.update(choices=files.list_output_files()) + ] + + if not text or not text.strip(): + gr.Warning("Please enter text in the input box") + return [ + None, + gr.update(choices=files.list_output_files()) + ] + + files.save_text(text) + result = api.text_to_speech(text, voice, format, speed) if result is None: gr.Warning("Failed to generate speech. Please try again.") - return { - components["output"]["audio_output"]: None, - components["output"]["output_files"]: gr.update(choices=files.list_output_files()) - } + return [ + None, + gr.update(choices=files.list_output_files()) + ] - return { - components["output"]["audio_output"]: result, - components["output"]["output_files"]: gr.update(choices=files.list_output_files(), value=os.path.basename(result)) - } + return [ + result, + gr.update(choices=files.list_output_files(), value=os.path.basename(result)) + ] + + def generate_from_file(selected_file, voice, format, speed): + """Generate speech from selected file""" + is_available, _ = api.check_api_status() + if not is_available: + gr.Warning("TTS Service is currently unavailable") + return [ + None, + gr.update(choices=files.list_output_files()) + ] + + if not selected_file: + gr.Warning("Please select a file") + return [ + None, + gr.update(choices=files.list_output_files()) + ] + + text = files.read_text_file(selected_file) + result = api.text_to_speech(text, voice, format, speed) + if result is None: + gr.Warning("Failed to generate speech. Please try again.") + return [ + None, + gr.update(choices=files.list_output_files()) + ] + + return [ + result, + gr.update(choices=files.list_output_files(), value=os.path.basename(result)) + ] def play_selected(file_path): if file_path and os.path.exists(file_path): return gr.update(value=file_path, visible=True) return gr.update(visible=False) + + def clear_files(voice, format, speed): + """Delete all input files and clear UI components while preserving model settings""" + files.delete_all_input_files() + return [ + gr.update(value=None, choices=[]), # file_select + None, # file_upload + gr.update(value=""), # file_preview + None, # audio_output + gr.update(choices=files.list_output_files()), # output_files + gr.update(value=voice), # voice + gr.update(value=format), # format + gr.update(value=speed) # speed + ] + + def clear_outputs(): + """Delete all output audio files and clear audio components""" + files.delete_all_output_files() + return [ + None, # audio_output + gr.update(choices=[], value=None), # output_files + gr.update(visible=False) # selected_audio + ] # Connect event handlers components["model"]["status_btn"].click( @@ -123,10 +194,54 @@ def setup_event_handlers(components: dict): outputs=[components["output"]["selected_audio"]] ) - components["model"]["submit"].click( - fn=generate_speech, + # Connect clear files button + components["input"]["clear_files"].click( + fn=clear_files, + inputs=[ + components["model"]["voice"], + components["model"]["format"], + components["model"]["speed"] + ], + outputs=[ + components["input"]["file_select"], + components["input"]["file_upload"], + components["input"]["file_preview"], + components["output"]["audio_output"], + components["output"]["output_files"], + components["model"]["voice"], + components["model"]["format"], + components["model"]["speed"] + ] + ) + + # Connect submit buttons for each tab + components["input"]["text_submit"].click( + fn=generate_from_text, inputs=[ components["input"]["text_input"], + components["model"]["voice"], + components["model"]["format"], + components["model"]["speed"] + ], + outputs=[ + components["output"]["audio_output"], + components["output"]["output_files"] + ] + ) + + # Connect clear outputs button + components["output"]["clear_outputs"].click( + fn=clear_outputs, + outputs=[ + components["output"]["audio_output"], + components["output"]["output_files"], + components["output"]["selected_audio"] + ] + ) + + components["input"]["file_submit"].click( + fn=generate_from_file, + inputs=[ components["input"]["file_select"], components["model"]["voice"], components["model"]["format"], diff --git a/ui/lib/interface.py b/ui/lib/interface.py index cfdada4..5361217 100644 --- a/ui/lib/interface.py +++ b/ui/lib/interface.py @@ -5,8 +5,8 @@ from .handlers import setup_event_handlers def create_interface(): """Create the main Gradio interface.""" - # Initial status check - is_available, available_voices = api.check_api_status() + # Skip initial status check - let the timer handle it + is_available, available_voices = False, [] with gr.Blocks( title="Kokoro TTS Demo", @@ -36,19 +36,55 @@ def create_interface(): # Add periodic status check with Timer def update_status(): - is_available, voices = api.check_api_status() - status = "Available" if is_available else "Unavailable" - return { - components["model"]["status_btn"]: gr.update(value=f"🔄 TTS Service: {status}"), - components["model"]["voice"]: gr.update(choices=voices, value=voices[0] if voices else None) - } + try: + is_available, voices = api.check_api_status() + status = "Available" if is_available else "Waiting for Service..." + + if is_available and voices: + # Service is available, update UI and stop timer + current_voice = components["model"]["voice"].value + default_voice = current_voice if current_voice in voices else voices[0] + # Return values in same order as outputs list + return [ + gr.update( + value=f"🔄 TTS Service: {status}", + interactive=True, + variant="secondary" + ), + gr.update(choices=voices, value=default_voice), + gr.update(active=False) # Stop timer + ] + + # Service not available yet, keep checking + return [ + gr.update( + value=f"⌛ TTS Service: {status}", + interactive=True, + variant="secondary" + ), + gr.update(choices=[], value=None), + gr.update(active=True) + ] + except Exception as e: + print(f"Error in status update: {str(e)}") + # On error, keep the timer running but show error state + return [ + gr.update( + value="❌ TTS Service: Connection Error", + interactive=True, + variant="secondary" + ), + gr.update(choices=[], value=None), + gr.update(active=True) + ] - timer = gr.Timer(10, active=True) # Check every 10 seconds + timer = gr.Timer(value=5) # Check every 5 seconds timer.tick( fn=update_status, outputs=[ components["model"]["status_btn"], - components["model"]["voice"] + components["model"]["voice"], + timer ] ) diff --git a/ui/tests/conftest.py b/ui/tests/conftest.py new file mode 100644 index 0000000..05ae58d --- /dev/null +++ b/ui/tests/conftest.py @@ -0,0 +1,9 @@ +import pytest +import gradio as gr + + +@pytest.fixture +def mock_gr_context(): + """Provides a context for testing Gradio components""" + with gr.Blocks(): + yield diff --git a/ui/tests/test_api.py b/ui/tests/test_api.py new file mode 100644 index 0000000..c9b37db --- /dev/null +++ b/ui/tests/test_api.py @@ -0,0 +1,129 @@ +import pytest +import requests +from unittest.mock import patch, mock_open +from ui.lib import api + + +@pytest.fixture +def mock_response(): + class MockResponse: + def __init__(self, json_data, status_code=200, content=b"audio data"): + self._json = json_data + self.status_code = status_code + self.content = content + + def json(self): + return self._json + + def raise_for_status(self): + if self.status_code != 200: + raise requests.exceptions.HTTPError(f"HTTP {self.status_code}") + + return MockResponse + + +def test_check_api_status_success(mock_response): + """Test successful API status check""" + mock_data = {"voices": ["voice1", "voice2"]} + with patch("requests.get", return_value=mock_response(mock_data)): + status, voices = api.check_api_status() + assert status is True + assert voices == ["voice1", "voice2"] + + +def test_check_api_status_no_voices(mock_response): + """Test API response with no voices""" + with patch("requests.get", return_value=mock_response({"voices": []})): + status, voices = api.check_api_status() + assert status is False + assert voices == [] + + +def test_check_api_status_timeout(): + """Test API timeout""" + with patch("requests.get", side_effect=requests.exceptions.Timeout): + status, voices = api.check_api_status() + assert status is False + assert voices == [] + + +def test_check_api_status_connection_error(): + """Test API connection error""" + with patch("requests.get", side_effect=requests.exceptions.ConnectionError): + status, voices = api.check_api_status() + assert status is False + assert voices == [] + + +def test_text_to_speech_success(mock_response, tmp_path): + """Test successful speech generation""" + with patch("requests.post", return_value=mock_response({})), \ + patch("ui.lib.api.OUTPUTS_DIR", str(tmp_path)), \ + patch("builtins.open", mock_open()) as mock_file: + + result = api.text_to_speech("test text", "voice1", "mp3", 1.0) + + assert result is not None + assert "output_" in result + assert result.endswith(".mp3") + mock_file.assert_called_once() + + +def test_text_to_speech_empty_text(): + """Test speech generation with empty text""" + result = api.text_to_speech("", "voice1", "mp3", 1.0) + assert result is None + + +def test_text_to_speech_timeout(): + """Test speech generation timeout""" + with patch("requests.post", side_effect=requests.exceptions.Timeout): + result = api.text_to_speech("test", "voice1", "mp3", 1.0) + assert result is None + + +def test_text_to_speech_request_error(): + """Test speech generation request error""" + with patch("requests.post", side_effect=requests.exceptions.RequestException): + result = api.text_to_speech("test", "voice1", "mp3", 1.0) + assert result is None + + +def test_get_status_html_available(): + """Test status HTML generation for available service""" + html = api.get_status_html(True) + assert "green" in html + assert "Available" in html + + +def test_get_status_html_unavailable(): + """Test status HTML generation for unavailable service""" + html = api.get_status_html(False) + assert "red" in html + assert "Unavailable" in html + + +def test_text_to_speech_api_params(mock_response, tmp_path): + """Test correct API parameters are sent""" + with patch("requests.post") as mock_post, \ + patch("ui.lib.api.OUTPUTS_DIR", str(tmp_path)), \ + patch("builtins.open", mock_open()): + + mock_post.return_value = mock_response({}) + api.text_to_speech("test text", "voice1", "mp3", 1.5) + + mock_post.assert_called_once() + args, kwargs = mock_post.call_args + + # Check request body + assert kwargs["json"] == { + "model": "kokoro", + "input": "test text", + "voice": "voice1", + "response_format": "mp3", + "speed": 1.5 + } + + # Check headers and timeout + assert kwargs["headers"] == {"Content-Type": "application/json"} + assert kwargs["timeout"] == 300 diff --git a/ui/tests/test_components.py b/ui/tests/test_components.py new file mode 100644 index 0000000..9ddb1ad --- /dev/null +++ b/ui/tests/test_components.py @@ -0,0 +1,116 @@ +import pytest +import gradio as gr +from ui.lib.components.model import create_model_column +from ui.lib.components.output import create_output_column +from ui.lib.config import AUDIO_FORMATS + + +def test_create_model_column_structure(): + """Test that create_model_column returns the expected structure""" + voice_ids = ["voice1", "voice2"] + column, components = create_model_column(voice_ids) + + # Test return types + assert isinstance(column, gr.Column) + assert isinstance(components, dict) + + # Test expected components presence + expected_components = { + "status_btn", + "voice", + "format", + "speed" + } + assert set(components.keys()) == expected_components + + # Test component types + assert isinstance(components["status_btn"], gr.Button) + assert isinstance(components["voice"], gr.Dropdown) + assert isinstance(components["format"], gr.Dropdown) + assert isinstance(components["speed"], gr.Slider) + + +def test_model_column_default_values(): + """Test the default values of model column components""" + voice_ids = ["voice1", "voice2"] + _, components = create_model_column(voice_ids) + + # Test voice dropdown + # Gradio Dropdown converts choices to (value, label) tuples + expected_choices = [(voice_id, voice_id) for voice_id in voice_ids] + assert components["voice"].choices == expected_choices + # Value is not converted to tuple format for the value property + assert components["voice"].value == voice_ids[0] + assert components["voice"].interactive is True + + # Test format dropdown + # Gradio Dropdown converts choices to (value, label) tuples + expected_format_choices = [(fmt, fmt) for fmt in AUDIO_FORMATS] + assert components["format"].choices == expected_format_choices + assert components["format"].value == "mp3" + + # Test speed slider + assert components["speed"].minimum == 0.5 + assert components["speed"].maximum == 2.0 + assert components["speed"].value == 1.0 + assert components["speed"].step == 0.1 + + +def test_model_column_no_voices(): + """Test model column creation with no voice IDs""" + _, components = create_model_column() + + assert components["voice"].choices == [] + assert components["voice"].value is None + + +def test_create_output_column_structure(): + """Test that create_output_column returns the expected structure""" + column, components = create_output_column() + + # Test return types + assert isinstance(column, gr.Column) + assert isinstance(components, dict) + + # Test expected components presence + expected_components = { + "audio_output", + "output_files", + "play_btn", + "selected_audio", + "clear_outputs" + } + assert set(components.keys()) == expected_components + + # Test component types + assert isinstance(components["audio_output"], gr.Audio) + assert isinstance(components["output_files"], gr.Dropdown) + assert isinstance(components["play_btn"], gr.Button) + assert isinstance(components["selected_audio"], gr.Audio) + assert isinstance(components["clear_outputs"], gr.Button) + + +def test_output_column_configuration(): + """Test the configuration of output column components""" + _, components = create_output_column() + + # Test audio output configuration + assert components["audio_output"].label == "Generated Speech" + assert components["audio_output"].type == "filepath" + + # Test output files dropdown + assert components["output_files"].label == "Previous Outputs" + assert components["output_files"].allow_custom_value is False + + # Test play button + assert components["play_btn"].value == "▶️ Play Selected" + assert components["play_btn"].size == "sm" + + # Test selected audio configuration + assert components["selected_audio"].label == "Selected Output" + assert components["selected_audio"].type == "filepath" + assert components["selected_audio"].visible is False + + # Test clear outputs button + assert components["clear_outputs"].size == "sm" + assert components["clear_outputs"].variant == "secondary" diff --git a/ui/tests/test_files.py b/ui/tests/test_files.py new file mode 100644 index 0000000..aaa0fe8 --- /dev/null +++ b/ui/tests/test_files.py @@ -0,0 +1,195 @@ +import os +import pytest +from unittest.mock import patch +from ui.lib import files +from ui.lib.config import AUDIO_FORMATS + + +@pytest.fixture +def mock_dirs(tmp_path): + """Create temporary input and output directories""" + inputs_dir = tmp_path / "inputs" + outputs_dir = tmp_path / "outputs" + inputs_dir.mkdir() + outputs_dir.mkdir() + + with patch("ui.lib.files.INPUTS_DIR", str(inputs_dir)), patch( + "ui.lib.files.OUTPUTS_DIR", str(outputs_dir) + ): + yield inputs_dir, outputs_dir + + +def test_list_input_files_empty(mock_dirs): + """Test listing input files from empty directory""" + assert files.list_input_files() == [] + + +def test_list_input_files(mock_dirs): + """Test listing input files with various files""" + inputs_dir, _ = mock_dirs + + # Create test files + (inputs_dir / "test1.txt").write_text("content1") + (inputs_dir / "test2.txt").write_text("content2") + (inputs_dir / "nottext.pdf").write_text("should not be listed") + + result = files.list_input_files() + assert len(result) == 2 + assert "test1.txt" in result + assert "test2.txt" in result + assert "nottext.pdf" not in result + + +def test_list_output_files_empty(mock_dirs): + """Test listing output files from empty directory""" + assert files.list_output_files() == [] + + +def test_list_output_files(mock_dirs): + """Test listing output files with various formats""" + _, outputs_dir = mock_dirs + + # Create test files for each format + for fmt in AUDIO_FORMATS: + (outputs_dir / f"test.{fmt}").write_text("dummy content") + (outputs_dir / "test.txt").write_text("should not be listed") + + result = files.list_output_files() + assert len(result) == len(AUDIO_FORMATS) + for fmt in AUDIO_FORMATS: + assert any(f".{fmt}" in file for file in result) + + +def test_read_text_file_empty_filename(mock_dirs): + """Test reading with empty filename""" + assert files.read_text_file("") == "" + + +def test_read_text_file_nonexistent(mock_dirs): + """Test reading nonexistent file""" + assert files.read_text_file("nonexistent.txt") == "" + + +def test_read_text_file_success(mock_dirs): + """Test successful file reading""" + inputs_dir, _ = mock_dirs + content = "Test content\nMultiple lines" + (inputs_dir / "test.txt").write_text(content) + + assert files.read_text_file("test.txt") == content + + +def test_save_text_empty(mock_dirs): + """Test saving empty text""" + assert files.save_text("") is None + assert files.save_text(" ") is None + + +def test_save_text_auto_filename(mock_dirs): + """Test saving text with auto-generated filename""" + inputs_dir, _ = mock_dirs + + # First save + filename1 = files.save_text("content1") + assert filename1 == "input_1.txt" + assert (inputs_dir / filename1).read_text() == "content1" + + # Second save + filename2 = files.save_text("content2") + assert filename2 == "input_2.txt" + assert (inputs_dir / filename2).read_text() == "content2" + + +def test_save_text_custom_filename(mock_dirs): + """Test saving text with custom filename""" + inputs_dir, _ = mock_dirs + + filename = files.save_text("content", "custom.txt") + assert filename == "custom.txt" + assert (inputs_dir / filename).read_text() == "content" + + +def test_save_text_duplicate_filename(mock_dirs): + """Test saving text with duplicate filename""" + inputs_dir, _ = mock_dirs + + # First save + filename1 = files.save_text("content1", "test.txt") + assert filename1 == "test.txt" + + # Save with same filename + filename2 = files.save_text("content2", "test.txt") + assert filename2 == "test_1.txt" + + assert (inputs_dir / "test.txt").read_text() == "content1" + assert (inputs_dir / "test_1.txt").read_text() == "content2" + + +def test_delete_all_input_files(mock_dirs): + """Test deleting all input files""" + inputs_dir, _ = mock_dirs + + # Create test files + (inputs_dir / "test1.txt").write_text("content1") + (inputs_dir / "test2.txt").write_text("content2") + (inputs_dir / "keep.pdf").write_text("should not be deleted") + + assert files.delete_all_input_files() is True + remaining_files = list(inputs_dir.iterdir()) + assert len(remaining_files) == 1 + assert remaining_files[0].name == "keep.pdf" + + +def test_delete_all_output_files(mock_dirs): + """Test deleting all output files""" + _, outputs_dir = mock_dirs + + # Create test files + for fmt in AUDIO_FORMATS: + (outputs_dir / f"test.{fmt}").write_text("dummy content") + (outputs_dir / "keep.txt").write_text("should not be deleted") + + assert files.delete_all_output_files() is True + remaining_files = list(outputs_dir.iterdir()) + assert len(remaining_files) == 1 + assert remaining_files[0].name == "keep.txt" + + +def test_process_uploaded_file_empty_path(mock_dirs): + """Test processing empty file path""" + assert files.process_uploaded_file("") is False + + +def test_process_uploaded_file_invalid_extension(mock_dirs, tmp_path): + """Test processing file with invalid extension""" + test_file = tmp_path / "test.pdf" + test_file.write_text("content") + assert files.process_uploaded_file(str(test_file)) is False + + +def test_process_uploaded_file_success(mock_dirs, tmp_path): + """Test successful file upload processing""" + inputs_dir, _ = mock_dirs + + # Create source file + source_file = tmp_path / "test.txt" + source_file.write_text("test content") + + assert files.process_uploaded_file(str(source_file)) is True + assert (inputs_dir / "test.txt").read_text() == "test content" + + +def test_process_uploaded_file_duplicate(mock_dirs, tmp_path): + """Test processing file with duplicate name""" + inputs_dir, _ = mock_dirs + + # Create existing file + (inputs_dir / "test.txt").write_text("existing content") + + # Create source file + source_file = tmp_path / "test.txt" + source_file.write_text("new content") + + assert files.process_uploaded_file(str(source_file)) is True + assert (inputs_dir / "test.txt").read_text() == "existing content" + assert (inputs_dir / "test_1.txt").read_text() == "new content" diff --git a/ui/tests/test_handlers.py b/ui/tests/test_handlers.py new file mode 100644 index 0000000..86a71b0 --- /dev/null +++ b/ui/tests/test_handlers.py @@ -0,0 +1,4 @@ +""" +Drop all tests for now. The Gradio event system is too complex to test properly. +We'll need to find a better way to test the UI functionality. +""" diff --git a/ui/tests/test_input.py b/ui/tests/test_input.py new file mode 100644 index 0000000..807a483 --- /dev/null +++ b/ui/tests/test_input.py @@ -0,0 +1,74 @@ +import pytest +import gradio as gr +from ui.lib.components.input import create_input_column + + +def test_create_input_column_structure(): + """Test that create_input_column returns the expected structure""" + column, components = create_input_column() + + # Test the return types + assert isinstance(column, gr.Column) + assert isinstance(components, dict) + + # Test that all expected components are present + expected_components = { + "tabs", + "text_input", + "file_select", + "file_upload", + "file_preview", + "text_submit", + "file_submit", + "clear_files", + } + assert set(components.keys()) == expected_components + + # Test component types + assert isinstance(components["tabs"], gr.Tabs) + assert isinstance(components["text_input"], gr.Textbox) + assert isinstance(components["file_select"], gr.Dropdown) + assert isinstance(components["file_upload"], gr.File) + assert isinstance(components["file_preview"], gr.Textbox) + assert isinstance(components["text_submit"], gr.Button) + assert isinstance(components["file_submit"], gr.Button) + assert isinstance(components["clear_files"], gr.Button) + + +def test_text_input_configuration(): + """Test the text input component configuration""" + _, components = create_input_column() + text_input = components["text_input"] + + assert text_input.label == "Text to speak" + assert text_input.placeholder == "Enter text here..." + assert text_input.lines == 4 + + +def test_file_upload_configuration(): + """Test the file upload component configuration""" + _, components = create_input_column() + file_upload = components["file_upload"] + + assert file_upload.label == "Upload Text File (.txt)" + assert file_upload.file_types == [".txt"] + + +def test_button_configurations(): + """Test the button configurations""" + _, components = create_input_column() + + # Test text submit button + assert components["text_submit"].value == "Generate Speech" + assert components["text_submit"].variant == "primary" + assert components["text_submit"].size == "lg" + + # Test file submit button + assert components["file_submit"].value == "Generate Speech" + assert components["file_submit"].variant == "primary" + assert components["file_submit"].size == "lg" + + # Test clear files button + assert components["clear_files"].value == "Clear Files" + assert components["clear_files"].variant == "secondary" + assert components["clear_files"].size == "lg" diff --git a/ui/tests/test_interface.py b/ui/tests/test_interface.py new file mode 100644 index 0000000..550591f --- /dev/null +++ b/ui/tests/test_interface.py @@ -0,0 +1,139 @@ +import pytest +import gradio as gr +from unittest.mock import patch, MagicMock, PropertyMock +from ui.lib.interface import create_interface + + +@pytest.fixture +def mock_timer(): + """Create a mock timer with events property""" + class MockEvent: + def __init__(self, fn): + self.fn = fn + + class MockTimer: + def __init__(self): + self._fn = None + self.value = 5 + + @property + def events(self): + return [MockEvent(self._fn)] if self._fn else [] + + def tick(self, fn, outputs): + self._fn = fn + + return MockTimer() + + +def test_create_interface_structure(): + """Test the basic structure of the created interface""" + with patch("ui.lib.api.check_api_status", return_value=(False, [])): + demo = create_interface() + + # Test interface type and theme + assert isinstance(demo, gr.Blocks) + assert demo.title == "Kokoro TTS Demo" + assert isinstance(demo.theme, gr.themes.Monochrome) + + +def test_interface_html_links(): + """Test that HTML links are properly configured""" + with patch("ui.lib.api.check_api_status", return_value=(False, [])): + demo = create_interface() + + # Find HTML component + html_components = [ + comp for comp in demo.blocks.values() + if isinstance(comp, gr.HTML) + ] + assert len(html_components) > 0 + html = html_components[0] + + # Check for required links + assert 'href="https://huggingface.co/hexgrad/Kokoro-82M"' in html.value + assert 'href="https://github.com/remsky/Kokoro-FastAPI"' in html.value + assert "Kokoro-82M HF Repo" in html.value + assert "Kokoro-FastAPI Repo" in html.value + + +def test_update_status_available(mock_timer): + """Test status update when service is available""" + voices = ["voice1", "voice2"] + with patch("ui.lib.api.check_api_status", return_value=(True, voices)), \ + patch("gradio.Timer", return_value=mock_timer): + demo = create_interface() + + # Get the update function + update_fn = mock_timer.events[0].fn + + # Test update with available service + updates = update_fn() + + assert "Available" in updates[0]["value"] + assert updates[1]["choices"] == voices + assert updates[1]["value"] == voices[0] + assert updates[2]["active"] is False # Timer should stop + + +def test_update_status_unavailable(mock_timer): + """Test status update when service is unavailable""" + with patch("ui.lib.api.check_api_status", return_value=(False, [])), \ + patch("gradio.Timer", return_value=mock_timer): + demo = create_interface() + update_fn = mock_timer.events[0].fn + + updates = update_fn() + + assert "Waiting for Service" in updates[0]["value"] + assert updates[1]["choices"] == [] + assert updates[1]["value"] is None + assert updates[2]["active"] is True # Timer should continue + + +def test_update_status_error(mock_timer): + """Test status update when an error occurs""" + with patch("ui.lib.api.check_api_status", side_effect=Exception("Test error")), \ + patch("gradio.Timer", return_value=mock_timer): + demo = create_interface() + update_fn = mock_timer.events[0].fn + + updates = update_fn() + + assert "Connection Error" in updates[0]["value"] + assert updates[1]["choices"] == [] + assert updates[1]["value"] is None + assert updates[2]["active"] is True # Timer should continue + + +def test_timer_configuration(mock_timer): + """Test timer configuration""" + with patch("ui.lib.api.check_api_status", return_value=(False, [])), \ + patch("gradio.Timer", return_value=mock_timer): + demo = create_interface() + + assert mock_timer.value == 5 # Check interval is 5 seconds + assert len(mock_timer.events) == 1 # Should have one event handler + + +def test_interface_components_presence(): + """Test that all required components are present""" + with patch("ui.lib.api.check_api_status", return_value=(False, [])): + demo = create_interface() + + # Check for main component sections + components = { + comp.label for comp in demo.blocks.values() + if hasattr(comp, 'label') and comp.label + } + + required_components = { + "Text to speak", + "Voice", + "Audio Format", + "Speed", + "Generated Speech", + "Previous Outputs" + } + + assert required_components.issubset(components)