File size: 6,579 Bytes
1778e91
 
 
 
4033555
1778e91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4033555
1778e91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4033555
 
 
 
 
 
 
1778e91
 
 
 
 
 
 
 
 
4033555
 
1778e91
 
 
 
 
 
 
 
4033555
1778e91
 
 
4033555
1778e91
 
 
67d3ff8
 
 
 
 
1778e91
 
 
 
 
 
 
 
 
 
 
 
 
67d3ff8
 
 
340bc5b
 
67d3ff8
1778e91
 
 
 
 
 
 
67d3ff8
 
 
340bc5b
 
67d3ff8
1778e91
 
 
 
4033555
1778e91
 
 
 
 
67d3ff8
1778e91
 
 
67d3ff8
1778e91
67d3ff8
 
1778e91
 
 
67d3ff8
1778e91
 
 
67d3ff8
1778e91
67d3ff8
 
1778e91
67d3ff8
 
 
 
 
 
 
 
 
 
 
 
 
1778e91
67d3ff8
1778e91
 
 
 
4033555
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import asyncio
import os
import time
from dataclasses import dataclass
from typing import List, Optional, AsyncGenerator, Tuple
import gradio as gr
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from logger import setup_logger, log_execution_time, log_async_execution_time
from api_clients import OpenRouterClient, ElevenLabsClient

load_dotenv()

console = Console()
logger = setup_logger("interface")

@log_async_execution_time(logger)
async def create_podcast(
    url: str,
    prompt: str,
    elevenlabs_key: str,
    voice_id: str,
    openrouter_key: str,
    model_id: str,
) -> Tuple[Optional[str], str]:
    """
    Create a podcast through a multi-step process:
    1. Content extraction from URL
    2. Script generation using AI
    3. Voice synthesis
    """
    logger.info(f"Starting podcast creation for URL: {url}")
    logger.debug(f"Parameters - Voice: {voice_id}, Model: {model_id}")
    logger.debug(f"Prompt length: {len(prompt)} chars")
    
    try:
        # Initialize clients with validation
        logger.debug("Initializing API clients")
        openrouter = OpenRouterClient(openrouter_key)
        elevenlabs = ElevenLabsClient(elevenlabs_key)
        
        # Phase 1: Content scraping
        logger.info("Phase 1/3: Content scraping")
        if not url.startswith(('http://', 'https://')):
            raise ValueError("URL must start with http:// or https://")
            
        logger.debug("Initializing LLM and browser agent")
        llm = ChatOpenAI(model="gpt-4")
        task = f"Visit this URL: {url} and extract the main content. Summarize it in a clear and concise way."
        content = await llm.apredict(task)
        logger.debug(f"Scraped content length: {len(content)} chars")
        
        # Phase 2: Script generation
        logger.info("Phase 2/3: Script generation")
        script = await openrouter.generate_script(content, prompt, model_id)
        logger.debug(f"Generated script length: {len(script)} chars")
        
        # Phase 3: Audio synthesis
        logger.info("Phase 3/3: Audio generation")
        audio = await elevenlabs.generate_audio(script, voice_id)
        logger.debug(f"Generated audio data received")
        
        # Save output
        audio_path = f"podcast_{int(time.time())}.mp3"
        logger.debug(f"Saving audio to: {audio_path}")
        with open(audio_path, "wb") as f:
            f.write(audio)
        
        logger.info("Podcast creation completed successfully")
        return audio_path, "Podcast created successfully!"
        
    except Exception as e:
        logger.error("Podcast creation failed", exc_info=True)
        return None, f"Error: {str(e)}"

def create_ui():
    logger.info("Initializing Gradio interface")
    
    # Default choices for dropdowns
    default_voices = [("", "Enter API key to load voices")]
    default_models = [("", "Enter API key to load models")]
    
    with gr.Blocks(title='PodcastCreator', theme=gr.themes.Soft()) as interface:
        with gr.Row():
            with gr.Column(scale=2):
                url_input = gr.Textbox(label='Source URL', placeholder='Enter the URL...')
                prompt = gr.Textbox(label='Podcast Topic', lines=3)
                
                with gr.Row():
                    with gr.Column():
                        elevenlabs_key = gr.Textbox(
                            label='ElevenLabs API Key',
                            type='password',
                            placeholder='Enter key...'
                        )
                        voice = gr.Dropdown(
                            label='Voice',
                            choices=default_voices,
                            value=None,
                            allow_custom_value=True
                        )
                    
                    with gr.Column():
                        openrouter_key = gr.Textbox(
                            label='OpenRouter API Key',
                            type='password',
                            placeholder='Enter key...'
                        )
                        model = gr.Dropdown(
                            label='AI Model',
                            choices=default_models,
                            value=None,
                            allow_custom_value=True
                        )
                
                submit_btn = gr.Button('Create Podcast', variant='primary')

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

        # Event handlers
        def update_voices(key):
            if not key:
                return gr.Dropdown(choices=default_voices, value=default_voices[0][0])
            try:
                client = ElevenLabsClient(key)
                voices = client.get_voices()
                return gr.Dropdown(choices=voices, value=voices[0][0] if voices else None)
            except Exception as e:
                logger.error(f"Failed to load voices: {e}")
                return gr.Dropdown(choices=[(None, f"Error: {str(e)}")], value=None)

        async def update_models(key):
            if not key:
                return gr.Dropdown(choices=default_models, value=default_models[0][0])
            try:
                client = OpenRouterClient(key)
                models = await client.get_models()
                return gr.Dropdown(choices=models, value=models[0][0] if models else None)
            except Exception as e:
                logger.error(f"Failed to load models: {e}")
                return gr.Dropdown(choices=[(None, f"Error: {str(e)}")], value=None)

        # Add error handling for the event handlers
        try:
            elevenlabs_key.change(fn=update_voices, inputs=elevenlabs_key, outputs=voice)
            openrouter_key.change(fn=update_models, inputs=openrouter_key, outputs=model)
            
            submit_btn.click(
                fn=create_podcast,
                inputs=[url_input, prompt, elevenlabs_key, voice, openrouter_key, model],
                outputs=[audio_output, status]
            )
        except Exception as e:
            logger.error(f"Failed to set up event handlers: {e}")
            raise

    logger.info("Gradio interface initialized successfully")
    return interface

if __name__ == '__main__':
    demo = create_ui()
    demo.queue().launch()