podcaster / app.py
marks
Integrated scraper
8757c5b
raw
history blame
5.01 kB
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
audio = await 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=[(name, id) for id, name in self.models], # Swap order for display
value=self.models[0][1] if len(self.models) > 1 else None,
type="index" # Use index to get the second element (id) from tuple
)
with gr.Column():
voice_model = gr.Dropdown(
label='Voice',
choices=[(name, id) for id, name in self.voices], # Swap order for display
value=self.voices[0][1] if len(self.voices) > 1 else None,
type="index" # Use index to get the second element (id) from tuple
)
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()