File size: 4,789 Bytes
9b11602
 
3404e9a
9b11602
bd07fc2
 
8757c5b
bd07fc2
 
9b11602
 
 
 
 
bd07fc2
 
 
8c7facc
 
bd07fc2
9b92628
 
bd07fc2
 
 
 
 
45c0e10
 
9b92628
bd07fc2
 
 
9b11602
bd07fc2
 
 
8757c5b
 
 
 
 
 
 
 
2ca982d
 
bd07fc2
 
 
 
9b11602
bd07fc2
 
 
 
9b11602
bd07fc2
 
 
 
 
 
 
 
 
 
 
0b6d459
25262d5
bd07fc2
 
 
 
 
25262d5
 
bd07fc2
 
0a42087
 
 
 
 
 
bd07fc2
9b11602
bd07fc2
0a42087
bd07fc2
 
9b11602
bd07fc2
 
0a42087
 
bd07fc2
9b11602
bd07fc2
42683f3
bd07fc2
 
 
 
9b92628
bd07fc2
 
 
9b92628
bd07fc2
 
9b11602
 
 
bd07fc2
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import asyncio
import os
import gradio as gr
from api_clients import OpenRouterClient, ElevenLabsClient
from logger import setup_logger
from config import Config
from scraper import scrape_url

logger = setup_logger("app")

# Default choices for dropdowns
default_voices = [("", "Enter API key to load voices")]
default_models = [("", "Enter API key to load models")]

class PodcasterUI:
    def __init__(self, config: Config):
        self.config = config
        self.router_client = OpenRouterClient(os.getenv('OPENROUTER_API_KEY', ''))
        self.elevenlabs_client = ElevenLabsClient(os.getenv('ELEVENLABS_API_KEY', ''))
        # Store models and voices as instance variables
        self.models = default_models
        self.voices = default_voices

    async def initialize(self):
        """Initialize API clients and fetch models/voices"""
        try:
            self.models = await self.router_client.get_models()
            # Since get_voices() might not be async, remove await
            self.voices = self.elevenlabs_client.get_voices()
            logger.info(f"Initialized with {len(self.voices)} voices and {len(self.models)} models")
        except Exception as e:
            logger.error("Failed to initialize API clients", exc_info=True)
            raise

    async def on_submit(self, content: str, model_id: str, voice_id: str, prompt: str = "") -> tuple:
        """Handle form submission with async API calls"""
        try:
            # First scrape the webpage content
            webpage_content = scrape_url(content)
            if not webpage_content:
                return "Failed to extract content from URL", None

            # Generate script using the scraped content
            script = await self.router_client.generate_script(webpage_content, prompt, model_id)
            
            # Generate audio from the script (now synchronous)
            audio = self.elevenlabs_client.generate_audio(script, voice_id)
            return script, audio
        except Exception as e:
            logger.error("Failed to generate podcast", exc_info=True)
            return str(e), None

    def create_ui(self) -> gr.Interface:
        with gr.Blocks(title='URL to Podcast Generator', theme='huggingface') as interface:
            gr.Markdown('# URL to Podcast Generator')
            gr.Markdown('Enter a URL to generate a podcast episode based on its content.')

            with gr.Row():
                with gr.Column(scale=2):
                    url_input = gr.Textbox(
                        label="Website URL",
                        placeholder="Enter the URL of the website you want to convert to a podcast"
                    )
                    
                    with gr.Row():
                        with gr.Column():
                            openrouter_model = gr.Dropdown(
                                label='AI Model',
                                choices=self.models,  # Each choice now has same id/display value
                                value=self.models[0][0] if len(self.models) > 1 else None,
                            )
                            
                        with gr.Column():
                            voice_model = gr.Dropdown(
                                label='Voice',
                                choices=[(id, name) for id, name in self.voices],
                                value=self.voices[0][0] if len(self.voices) > 1 else None,
                            )
                    
                    prompt_input = gr.Textbox(
                        label="Custom Prompt",
                        placeholder="Enter a custom prompt to guide the podcast generation (optional)",
                        lines=3
                    )
                    
                    submit_btn = gr.Button('Generate Podcast', variant='primary')

                with gr.Column(scale=1):
                    script_output = gr.Textbox(label="Generated Script", interactive=False)
                    audio_output = gr.Audio(label="Generated Podcast")
                    status = gr.Textbox(label='Status', interactive=False)

            submit_btn.click(
                fn=self.on_submit,
                inputs=[url_input, openrouter_model, voice_model, prompt_input],
                outputs=[script_output, audio_output]
            )

        return interface

def main():
    config = Config()
    app = PodcasterUI(config)
    
    # Initialize before creating UI
    loop = asyncio.get_event_loop()
    loop.run_until_complete(app.initialize())
    
    # Create UI with populated data
    interface = app.create_ui()
    interface.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=True
    )

if __name__ == "__main__":
    main()