File size: 3,769 Bytes
7dd982b
 
 
 
 
 
 
 
 
 
76e3793
 
b82995c
7dd982b
 
 
 
 
b82995c
7dd982b
b82995c
7dd982b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76e3793
 
 
 
b82995c
76e3793
 
 
 
 
 
 
 
 
b82995c
76e3793
 
 
 
 
 
 
 
 
 
7dd982b
 
 
 
 
 
b82995c
7dd982b
 
 
 
 
 
76e3793
7dd982b
76e3793
 
 
7dd982b
 
 
 
 
 
b82995c
 
 
 
 
 
 
 
7dd982b
b82995c
7dd982b
 
 
 
 
b82995c
 
7dd982b
 
 
 
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
import gradio as gr
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import HuggingFacePipeline
from transformers import pipeline
from gtts import gTTS
from bs4 import BeautifulSoup
import tempfile
import os
import requests
from PIL import Image, ImageDraw, ImageFont
import subprocess
import concurrent.futures

# CPU-friendly summarization model
summary_pipe = pipeline("text2text-generation", model="google/flan-t5-base", device=-1)
llm = HuggingFacePipeline(pipeline=summary_pipe)

# LangChain summarization prompt (short summary)
summary_prompt = PromptTemplate.from_template("""
Give a crisp and short summary of the following content (under 50 words):

{text}

Summary:
""")
summary_chain = LLMChain(llm=llm, prompt=summary_prompt)

def extract_main_content(url):
    try:
        response = requests.get(url, timeout=10)
        soup = BeautifulSoup(response.content, "html.parser")
        for tag in soup(["nav", "header", "footer", "aside", "script", "style", "noscript"]):
            tag.decompose()
        paragraphs = soup.find_all("p")
        content = "\n".join([p.get_text() for p in paragraphs if len(p.get_text()) > 60])
        return content.strip()
    except Exception as e:
        return f"Error extracting article content: {str(e)}"

def create_text_image(summary_text, image_path):
    img = Image.new("RGB", (1280, 720), color=(0, 0, 0))
    draw = ImageDraw.Draw(img)
    font = ImageFont.load_default()
    wrapped = summary_text[:512] + ('...' if len(summary_text) > 512 else '')
    draw.text((50, 50), wrapped, fill=(255, 255, 255), font=font)
    img.save(image_path)

def generate_video(image_path, audio_path, output_path):
    cmd = [
        "ffmpeg", "-y",
        "-loop", "1",
        "-i", image_path,
        "-i", audio_path,
        "-t", "15",
        "-c:v", "libx264",
        "-tune", "stillimage",
        "-c:a", "aac",
        "-b:a", "192k",
        "-pix_fmt", "yuv420p",
        "-shortest",
        output_path
    ]
    subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

def url_to_av_summary(url):
    try:
        article_text = extract_main_content(url)
        if article_text.startswith("Error"):
            return article_text, None

        article_text = article_text[:3000]  # Further truncated
        summary = summary_chain.run(text=article_text)

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

        image_path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
        video_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name

        create_text_image(summary, image_path)
        generate_video(image_path, audio_path, video_path)

        return summary, video_path

    except Exception as e:
        return f"Error: {str(e)}", None

def safe_summary_with_timeout(url, timeout_secs=60):
    with concurrent.futures.ThreadPoolExecutor() as executor:
        future = executor.submit(url_to_av_summary, url)
        try:
            return future.result(timeout=timeout_secs)
        except concurrent.futures.TimeoutError:
            return "⏱️ Processing took too long. Try a shorter article.", None

iface = gr.Interface(
    fn=safe_summary_with_timeout,
    inputs=gr.Textbox(label="Article URL", placeholder="Paste a news/blog URL here..."),
    outputs=[
        gr.Textbox(label="Summary"),
        gr.Video(label="Video Summary")
    ],
    title="🧠 Short AV Summary from URL",
    description="Extracts clean article content and creates a <15 second narrated video with a short crisp summary. 100% CPU-compatible."
)

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