import gradio as gr import tempfile, requests from langchain.chains import LLMChain from langchain.prompts import PromptTemplate from langchain_openai import ChatOpenAI from gtts import gTTS from bs4 import BeautifulSoup from PIL import Image, ImageDraw import ffmpeg import textwrap # Initialize OpenAI LLM llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.3) summary_prompt = PromptTemplate.from_template(""" Provide a crisp, promotional-style summary (under 50 words) of the following: {text} Summary: """) summary_chain = LLMChain(llm=llm, prompt=summary_prompt) # Extract top article paragraphs def extract_main_content(url): resp = requests.get(url, timeout=10) soup = BeautifulSoup(resp.content, "html.parser") for tag in soup(["nav","header","footer","aside","script","style","noscript"]): tag.decompose() paras = [p.get_text() for p in soup.find_all("p") if len(p.get_text()) > 60] return "\n".join(paras[:20]) or None # Gradient background def create_background(path, size=(1280,720)): img = Image.new("RGB", size) draw = ImageDraw.Draw(img) for y in range(size[1]): draw.line([(0,y),(size[0],y)], fill=(10+y//10,20+y//12,50+y//15)) img.save(path) # Generate AV summary def url_to_av_summary(url, duration): content = extract_main_content(url) if not content: return "Failed to extract content.", None summary = summary_chain.run(text=content[:3000]).replace('"','')[:300] # Wrap long summary to multiline wrapped_summary = textwrap.fill(summary, width=50).replace("\n", "\\n") # TTS audio = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name gTTS(text=summary).save(audio) # Background image bg = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name create_background(bg) # Build video stream video_stream = ffmpeg.input(bg, loop=1, framerate=1) text_opts = dict( fontfile="/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", text=wrapped_summary, fontcolor="white", fontsize=48, box=1, boxcolor="black@0.5", boxborderw=5, x="(w-text_w)/2", y=f"h-(t*(h+text_h)/{duration})" ) video = video_stream.drawtext(**text_opts).setpts('PTS') audio_stream = ffmpeg.input(audio) out_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name out = ffmpeg.output(video, audio_stream, out_path, vcodec="libx264", acodec="aac", pix_fmt="yuv420p", t=duration) out.run(quiet=True) return summary, out_path iface = gr.Interface( fn=url_to_av_summary, inputs=[gr.Textbox(label="Article URL"), gr.Radio([5,10], label="Duration (sec)", value=5)], outputs=[gr.Textbox(label="Summary"), gr.Video(label="AV Summary")], title="AV Summary Generator", description="Generate a promo-style AV summary (5 or 10s) using OpenAI + gTTS + ffmpeg-python." ) if __name__=='__main__': iface.launch()