File size: 2,937 Bytes
7dd982b
eec85c6
7dd982b
 
eec85c6
7dd982b
 
f06c20a
7dd982b
eec85c6
 
7dd982b
f06c20a
7dd982b
 
 
 
 
 
 
eec85c6
7dd982b
f06c20a
 
eec85c6
2b8e4f0
eec85c6
f06c20a
eec85c6
f06c20a
 
76e3793
eec85c6
 
 
76e3793
 
eec85c6
 
 
 
f06c20a
eec85c6
2b8e4f0
f06c20a
 
2b8e4f0
f06c20a
 
2b8e4f0
f06c20a
76e3793
f06c20a
eec85c6
f06c20a
 
eec85c6
f06c20a
eec85c6
f06c20a
76e3793
 
 
eec85c6
b82995c
7dd982b
eec85c6
 
 
 
 
 
 
 
 
 
 
7dd982b
 
f06c20a
eec85c6
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
import gradio as gr
import tempfile, subprocess, requests
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
from gtts import gTTS
from bs4 import BeautifulSoup
from PIL import Image, ImageDraw

# OpenAI LLM (fast + accurate)
llm = ChatOpenAI(model="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 relevant content from article
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(image_path, size=(1280,720)):
    img = Image.new("RGB", size)
    draw = ImageDraw.Draw(img)
    for y in range(size[1]):
        color = (10 + y//10, 20 + y//12, 50 + y//15)
        draw.line([(0, y), (size[0], y)], fill=color)
    img.save(image_path)

# AV generation logic with variable duration
def url_to_av_summary(url, duration):
    content = extract_main_content(url)
    if not content:
        return "Failed to extract article content.", None
    summary = summary_chain.run(text=content[:3000]).replace('"','')[:300]

    audio_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name
    gTTS(text=summary).save(audio_path)

    bg_path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
    create_background(bg_path)

    video_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
    cmd = [
        'ffmpeg', '-y',
        '-loop', '1', '-i', bg_path, '-i', audio_path,
        '-vf', (
            "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:text='" + summary +
            f"':fontcolor=white:fontsize=48:box=1:[email protected]:boxborderw=5:x=(w-text_w)/2:y=h-(t*(h+text_h)/{duration})"
        ),
        '-t', str(duration),
        '-c:v', 'libx264', '-c:a', 'aac', '-pix_fmt', 'yuv420p', '-shortest', video_path
    ]
    subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

    return summary, video_path

iface = gr.Interface(
    fn=url_to_av_summary,
    inputs=[
        gr.Textbox(label="Article URL"),
        gr.Radio([5, 10], label="Video Duration (sec)", value=5)
    ],
    outputs=[
        gr.Textbox(label="Summary"),
        gr.Video(label="Generated AV Summary")
    ],
    title="๐ŸŽž๏ธ AV Summary Generator (OpenAI Powered)",
    description="Generate a short AV video (5 or 10 seconds) summarizing any article. Uses OpenAI + gTTS + FFmpeg."
)

if __name__ == '__main__':
    iface.launch()