CoolFace
Apppublic

uxoxo/eb2ab

sourceHugging Faceapache-2.0updated 11mo agoView on Hugging Face
0likes
app_llm_processor.py467 linesDownload Raw Back to root
1#!/usr/bin/env python32"""3LLM Ebook Processor - Text Preprocessing Pipeline for TTS4Processes ebooks with LLM instructions, then converts to audiobook5 6Features:7- Multi-format ebook support (EPUB, PDF, MOBI, TXT, etc.)8- Smart text chunking strategies9- Cost & time estimates BEFORE processing10- LLM integration (OpenAI, Anthropic, Ollama)11- TTS integration with progress tracking12- Direct download links for audiobooks13 14Author: Claude Code15Date: 2025-10-1716"""17 18import gradio as gr19import os20import sys21from pathlib import Path22 23# Add lib directory to path for imports24sys.path.insert(0, str(Path(__file__).parent))25 26# Import our processing modules27from lib.ebook_extractor import extract_ebook_text28from lib.text_chunker import chunk_text29from lib.estimator import estimate_costs30from lib.llm_processor import process_with_llm31from lib.tts_integration import submit_to_tts, poll_tts_status32from lib.download_manager import get_download_link33 34# Import event handlers35from app_llm_processor_handlers import (36    handle_analyze,37    handle_confirm_processing,38    handle_llm_processing,39    handle_tts_conversion,40    handle_generate_downloads,41    current_job42)43 44 45def create_app():46    """Create the Gradio application"""47 48    with gr.Blocks(49        title="LLM Ebook Processor + TTS",50        theme=gr.themes.Soft(),51        css="""52        .estimate-box {53            background: #f0f9ff;54            border: 2px solid #0ea5e9;55            border-radius: 8px;56            padding: 20px;57            margin: 10px 0;58        }59        .cost-estimate {60            font-size: 24px;61            font-weight: bold;62            color: #0ea5e9;63        }64        .time-estimate {65            font-size: 20px;66            color: #059669;67        }68        """69    ) as app:70 71        gr.Markdown("""72        # πŸ“š LLM Ebook Processor + TTS73 74        Transform your ebooks with AI, then convert to audiobooks!75 76        **Complete Pipeline:**77        1. Upload ebook β†’ 2. Configure processing β†’ 3. See estimates β†’78        4. LLM processing β†’ 5. TTS conversion β†’ 6. Download audiobook79        """)80 81        # =================================================================82        # STEP 1: Upload & Configure83        # =================================================================84 85        with gr.Tab("1️⃣ Upload & Configure"):86            gr.Markdown("### πŸ“– Upload Your Ebook")87 88            ebook_file = gr.File(89                label="Ebook File",90                file_types=[".epub", ".pdf", ".mobi", ".txt", ".html", ".rtf"],91                type="filepath"92            )93 94            gr.Markdown("### πŸ”§ Chunking Strategy")95 96            chunk_strategy = gr.Radio(97                choices=[98                    "By Chapter (Semantic)",99                    "Fixed Size with Overlap",100                    "Sentence Boundaries"101                ],102                value="By Chapter (Semantic)",103                label="How to split the book"104            )105 106            with gr.Row():107                chunk_size = gr.Slider(108                    minimum=500,109                    maximum=8000,110                    value=4000,111                    step=500,112                    label="Chunk Size (tokens)",113                    info="Only for Fixed Size strategy"114                )115 116                chunk_overlap = gr.Slider(117                    minimum=0,118                    maximum=500,119                    value=200,120                    step=50,121                    label="Overlap (tokens)",122                    info="Maintains context between chunks"123                )124 125            gr.Markdown("### πŸ“ Processing Instructions")126 127            instruction_template = gr.Dropdown(128                choices=[129                    "Custom (enter below)",130                    "Modernize Language",131                    "Simplify for Children",132                    "Translate to Spanish",133                    "Convert to Casual Tone",134                    "Remove Old Grammar"135                ],136                value="Custom (enter below)",137                label="Instruction Template"138            )139 140            processing_instruction = gr.Textbox(141                label="Custom Instructions",142                placeholder="e.g., Convert this Victorian-era English to modern lay English while retaining all original meaning and literary nuance",143                lines=3,144                value="Convert this Victorian-era English to modern lay English while retaining all original meaning and literary nuance"145            )146 147            gr.Markdown("### πŸ€– LLM Provider")148 149            llm_provider = gr.Radio(150                choices=[151                    "Claude 3 Haiku (Fastest, Cheapest)",152                    "Claude 3.5 Sonnet (Balanced)",153                    "GPT-4o (Best Quality)",154                    "GPT-3.5 Turbo (Fast & Cheap)",155                    "Ollama (Free, Local - Slower)"156                ],157                value="Claude 3 Haiku (Fastest, Cheapest)",158                label="Choose LLM Provider"159            )160 161            gr.Markdown("### πŸŽ™οΈ Text-to-Speech")162 163            enable_tts = gr.Checkbox(164                label="Generate audiobook after LLM processing",165                value=True166            )167 168            with gr.Row(visible=True) as tts_options:169                tts_voice = gr.Dropdown(170                    choices=["Morgan Freeman", "David Attenborough", "Custom Voice"],171                    value="Morgan Freeman",172                    label="Voice"173                )174 175                tts_format = gr.Dropdown(176                    choices=["M4B", "MP3", "WAV"],177                    value="M4B",178                    label="Audio Format"179                )180 181            # Button to proceed to estimates182            analyze_btn = gr.Button(183                "πŸ“Š Analyze & Show Estimates",184                variant="primary",185                size="lg"186            )187 188        # =================================================================189        # STEP 2: Review Estimates190        # =================================================================191 192        with gr.Tab("2️⃣ Review Estimates") as estimates_tab:193            gr.Markdown("### πŸ“Š Processing Estimates")194 195            with gr.Column(elem_classes="estimate-box"):196                book_info = gr.Markdown("Upload a book to see estimates...")197 198                cost_breakdown = gr.Markdown()199                time_breakdown = gr.Markdown()200 201                alternative_options = gr.Markdown()202 203            with gr.Row():204                cancel_btn = gr.Button("❌ Cancel", variant="stop")205                edit_btn = gr.Button("✏️ Edit Settings")206                confirm_btn = gr.Button(207                    "βœ… Confirm & Start Processing",208                    variant="primary",209                    size="lg"210                )211 212        # =================================================================213        # STEP 3: LLM Processing214        # =================================================================215 216        with gr.Tab("3️⃣ LLM Processing") as llm_tab:217            gr.Markdown("### πŸ”„ Processing Book with AI")218 219            llm_status = gr.Markdown("**Phase 1/2:** LLM Text Processing")220 221            llm_progress = gr.Progress()222            llm_progress_bar = gr.Slider(223                minimum=0,224                maximum=100,225                value=0,226                label="Progress",227                interactive=False228            )229 230            llm_current_chunk = gr.Textbox(231                label="Current",232                value="Waiting to start...",233                interactive=False234            )235 236            with gr.Row():237                llm_time_info = gr.Textbox(238                    label="⏱️ Time",239                    value="Elapsed: 0s | Remaining: --",240                    interactive=False241                )242 243                llm_cost_info = gr.Textbox(244                    label="πŸ’° Cost",245                    value="Spent: $0.00 | Estimated: $0.00",246                    interactive=False247                )248 249            with gr.Row():250                pause_llm_btn = gr.Button("⏸️ Pause")251                cancel_llm_btn = gr.Button("❌ Cancel", variant="stop")252 253        # =================================================================254        # STEP 4: TTS Processing255        # =================================================================256 257        with gr.Tab("4️⃣ TTS Conversion") as tts_tab:258            gr.Markdown("### πŸ”„ Converting to Audiobook")259 260            tts_status = gr.Markdown("**Phase 2/2:** Text-to-Speech Conversion")261 262            tts_progress_bar = gr.Slider(263                minimum=0,264                maximum=100,265                value=0,266                label="Progress",267                interactive=False268            )269 270            tts_current_chapter = gr.Textbox(271                label="Current",272                value="Waiting for LLM to complete...",273                interactive=False274            )275 276            with gr.Row():277                tts_time_info = gr.Textbox(278                    label="⏱️ Time",279                    value="Total: 0 min | Remaining: --",280                    interactive=False281                )282 283                tts_cost_info = gr.Textbox(284                    label="πŸ’° Total Cost",285                    value="LLM: $0.00 | TTS: $0.00 | Total: $0.00",286                    interactive=False287                )288 289            with gr.Row():290                pause_tts_btn = gr.Button("⏸️ Pause")291                cancel_tts_btn = gr.Button("❌ Cancel", variant="stop")292 293        # =================================================================294        # STEP 5: Download Results295        # =================================================================296 297        with gr.Tab("5️⃣ Download") as download_tab:298            gr.Markdown("### βœ… Processing Complete!")299 300            completion_summary = gr.Markdown()301 302            gr.Markdown("### πŸ“₯ Downloads")303 304            with gr.Row():305                processed_text_file = gr.File(306                    label="πŸ“„ Processed Text (.txt)",307                    interactive=False308                )309 310                processed_epub_file = gr.File(311                    label="πŸ“„ Processed EPUB",312                    interactive=False313                )314 315            audiobook_file = gr.File(316                label="🎧 Audiobook (M4B)",317                interactive=False318            )319 320            with gr.Row():321                mp3_file = gr.File(label="MP3", interactive=False)322                wav_file = gr.File(label="WAV", interactive=False)323                ogg_file = gr.File(label="OGG", interactive=False)324 325            processing_report = gr.Textbox(326                label="πŸ“Š Processing Summary",327                lines=10,328                interactive=False329            )330 331            with gr.Row():332                process_another_btn = gr.Button(333                    "πŸ”„ Process Another Book",334                    variant="primary"335                )336                save_template_btn = gr.Button("⭐ Save Settings as Template")337 338        # =================================================================339        # Event Handlers340        # =================================================================341 342        # Step 1: Analyze button - Extract, chunk, and estimate costs343        analyze_btn.click(344            fn=handle_analyze,345            inputs=[346                ebook_file,347                chunk_strategy,348                chunk_size,349                chunk_overlap,350                llm_provider,351                enable_tts352            ],353            outputs=[354                book_info,355                cost_breakdown,356                time_breakdown,357                alternative_options358            ]359        )360 361        # Step 2: Confirm button - Start LLM processing362        def start_processing(instruction, provider):363            # Validate first364            validation_msg = handle_confirm_processing(instruction, provider)365 366            # If validation passes, start LLM processing367            if "βœ…" in validation_msg:368                # Store settings in current_job369                current_job['llm_provider'] = provider370                return handle_llm_processing(instruction, provider)371            else:372                # Return validation error373                return (validation_msg, "Elapsed: 0s | Waiting", "Spent: $0.00 | Waiting")374 375        confirm_btn.click(376            fn=start_processing,377            inputs=[378                processing_instruction,379                llm_provider380            ],381            outputs=[382                llm_status,383                llm_time_info,384                llm_cost_info385            ]386        )387 388        # Step 3: After LLM completes, auto-start TTS (if enabled)389        def auto_start_tts(voice, format_type, tts_enabled):390            if tts_enabled:391                current_job['tts_voice'] = voice392                current_job['tts_format'] = format_type393                return handle_tts_conversion(voice, format_type)394            else:395                # Skip TTS, go straight to downloads396                return (397                    "### ⏭️ TTS Skipped\n\nTTS was disabled. Proceed to download processed text.",398                    "Total: 0 min | Skipped",399                    "LLM: $0.00 | TTS: $0.00 | Total: $0.00"400                )401 402        # Wire TTS auto-start to a button for manual trigger403        # (In a real implementation, this would be triggered automatically after LLM completes)404        # For now, we'll need a manual trigger button405 406        # Step 4: Generate downloads407        def prepare_downloads():408            return handle_generate_downloads()409 410        # Add a helper function to load the download tab with data411        def on_download_tab_select():412            if current_job.get('audio_file') or current_job.get('processed_text'):413                return handle_generate_downloads()414            else:415                return (416                    "### ⏳ Waiting for Processing\n\nComplete LLM and TTS processing first.",417                    None, None, None, None, ""418                )419 420        # Wire up download tab to auto-populate when selected421        download_tab.select(422            fn=on_download_tab_select,423            outputs=[424                completion_summary,425                processed_text_file,426                audiobook_file,427                mp3_file,428                wav_file,429                processing_report430            ]431        )432 433        # Navigation helpers434        def go_to_tab(tab_name):435            """Helper to switch tabs programmatically"""436            pass  # Gradio handles this with .select()437 438        # Process another book - reset state439        def reset_job():440            current_job.clear()441            current_job.update({442                'metadata': None,443                'chapters': None,444                'chunks': None,445                'estimate': None,446                'processed_text': None,447                'job_id': None448            })449            return "Upload a new book to start..."450 451        process_another_btn.click(452            fn=reset_job,453            outputs=[book_info]454        )455 456    return app457 458 459if __name__ == "__main__":460    app = create_app()461    app.launch(462        server_name="0.0.0.0",463        server_port=7861,  # Different port from main ebook2audiobook464        share=False,465        show_error=True466    )467