#Codes from killerz3/PodGen & eswardivi/Podcastify import json import spaces import httpx import asyncio import edge_tts import torch import gradio as gr import gradio_client from pydub import AudioSegment from transformers import AutoModelForCausalLM, AutoTokenizer from moviepy.editor import AudioFileClip, concatenate_audioclips system_prompt = ''' You are an educational podcast generator. You have to create a podcast between Alice and Bob that gives an overview of the News given by the user. Please provide the script in the following JSON format directly and only include it: { "title": "[string]", "content": { "Alice_0": "[string]", "BOB_0": "[string]", ... } } Please note that the text you generate now must be based on the tone of people's daily life. And the punctuation marks only include commas and periods. ''' DESCRIPTION = '''

Musen

A podcast talking about the link's content you provided.

🔎 Paste a website link with http/https.

🦕 Generate podcast.

''' css = """ h1 { text-align: center; display: block; } footer { display:none !important } """ model = AutoModelForCausalLM.from_pretrained( "Qwen/Qwen1.5-1.8B-Chat", torch_dtype="auto", device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen1.5-1.8B-Chat") def validate_url(url): try: response = httpx.get(url, timeout=60.0) response.raise_for_status() return response.text except httpx.RequestError as e: return f"An error occurred while requesting {url}: {str(e)}" except httpx.HTTPStatusError as e: return f"Error response {e.response.status_code} while requesting {url}" except Exception as e: return f"An unexpected error occurred: {str(e)}" def fetch_text(url): print("Entered Webpage Extraction") prefix_url = "https://r.jina.ai/" full_url = prefix_url + url print(full_url) print("Exited Webpage Extraction") return validate_url(full_url) async def text_to_speech(text, voice, filename): communicate = edge_tts.Communicate(text, voice) await communicate.save(filename) async def gen_show(script): title = script['title'] content = script['content'] temp_files = [] tasks = [] for key, text in content.items(): speaker = key.split('_')[0] # Extract the speaker name index = key.split('_')[1] # Extract the dialogue index voice = "en-US-JennyNeural" if speaker == "Alice" else "en-US-GuyNeural" # Create temporary file for each speaker's dialogue temp_file = tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) temp_files.append(temp_file.name) filename = temp_file.name tasks.append(text_to_speech(text, voice, filename)) print(f"Generated audio for {speaker}_{index}: {filename}") await asyncio.gather(*tasks) # Combine the audio files using moviepy audio_clips = [AudioFileClip(temp_file) for temp_file in temp_files] combined = concatenate_audioclips(audio_clips) # Create temporary file for the combined output output_filename = tempfile.NamedTemporaryFile(suffix='.mp3', delete=False).name # Save the combined file combined.write_audiofile(output_filename) print(f"Combined audio saved as: {output_filename}") # Clean up temporary files for temp_file in temp_files: os.remove(temp_file) print(f"Deleted temporary file: {temp_file}") return output_filename @spaces.GPU(duration=100) def generator(messages): answer = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) model_inputs = tokenizer([answer], return_tensors="pt").to(0) generated_ids = model.generate( model_inputs.input_ids, max_new_tokens=512 ) generated_ids = [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ] results = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] return results async def main(link): if not link.startswith("http://") and not link.startswith("https://"): return "URL must start with 'http://' or 'https://'",None text = fetch_text(link) if "Error" in text: return text, None prompt = f"News: {text}, json:" messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}, ] generated_script = generator(messages) print("Generated Script:"+generated_script) # Check if the generated_script is empty or not valid JSON if not generated_script or not generated_script.strip().startswith('{'): raise ValueError("Failed to generate a valid script.") script_json = json.loads(generated_script) # Use the generated script as input output_filename = await gen_show(script_json) print("Output File:"+output_filename) # Read the generated audio file return output_filename with gr.Blocks(theme='soft', css=css, title="Musen") as iface: with gr.Accordion(""): gr.Markdown(DESCRIPTION) with gr.Row(): output_box = gr.Audio(label="Podcast", type="filepath", interactive=False, autoplay=True, elem_classes="audio") # Create an output textbox with gr.Row(): input_box = gr.Textbox(label="Link", placeholder="Enter a http link") with gr.Row(): submit_btn = gr.Button("🚀 Send") # Create a submit button clear_btn = gr.ClearButton(output_box, value="🗑️ Clear") # Create a clear button # Set up the event listeners submit_btn.click(main, inputs=input_box, outputs=output_box) #gr.close_all() iface.queue().launch(show_api=False) # Launch the Gradio interface