File size: 5,911 Bytes
3036801
 
 
 
 
 
 
 
 
 
 
 
 
c2e808d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef7b107
923f3ac
 
ef7b107
923f3ac
3036801
 
ef7b107
3036801
ef7b107
 
3036801
 
 
ef7b107
3036801
c2e808d
 
3036801
 
 
 
 
ef7b107
3036801
ef7b107
 
3036801
c2e808d
 
 
ef7b107
c2e808d
 
ef7b107
 
 
 
 
3036801
ef7b107
 
c2e808d
ef7b107
 
 
c2e808d
 
ef7b107
c2e808d
3036801
 
ef7b107
3036801
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# app.py
import os
import subprocess
import glob
import re
import traceback
import gradio as gr
from openai import OpenAI

# Load OpenAI key from environment (Hugging Face Spaces -> Settings -> Secrets)
openai_api_key = os.getenv("OPENAI_API_KEY")
openai = OpenAI(api_key=openai_api_key)

# def download_audio(youtube_url):
#     try:
#         output_template = "/tmp/downloaded_audio.%(ext)s"

#         # Remove any old files
#         for f in glob.glob("/tmp/downloaded_audio.*"):
#             os.remove(f)

#         command = [
#             "yt-dlp", "-f", "bestaudio",
#             "--extract-audio", "--audio-format", "mp3",
#             "--audio-quality", "0",
#             "-o", output_template,
#             youtube_url
#         ]

#         result = subprocess.run(command, capture_output=True, text=True)
#         print("stdout:\n", result.stdout)
#         print("stderr:\n", result.stderr)

#         if result.returncode != 0:
#             raise RuntimeError(f"yt-dlp failed: {result.stderr}")

#         files = glob.glob("/tmp/downloaded_audio.*")
#         if not files:
#             raise FileNotFoundError("No audio file downloaded.")

#         return files[0]
#     except Exception as e:
#         raise RuntimeError(f"Download error: {e}")

from pytube import YouTube

def clean_youtube_url(url):
    match = re.search(r"(?:v=|shorts/)([a-zA-Z0-9_-]{11})", url)
    video_id = match.group(1) if match else None
    return f"https://www.youtube.com/watch?v={video_id}" if video_id else None

def download_audio(youtube_url):
    try:
        print(f"โ–ถ๏ธ Original URL: {youtube_url}")
        output_template = "/tmp/downloaded_audio.%(ext)s"

        # Cleanup old files
        for f in glob.glob("/tmp/downloaded_audio.*"):
            os.remove(f)

        # โœ… Try yt-dlp first
        command = [
            "yt-dlp",
            "-f", "bestaudio",
            "--extract-audio", "--audio-format", "mp3",
            "--audio-quality", "0",
            "-o", output_template,
            youtube_url
        ]
        print("๐Ÿ“ก Running yt-dlp...")
        result = subprocess.run(command, capture_output=True, text=True)
        print("๐Ÿ“œ yt-dlp stdout:", result.stdout)
        print("๐Ÿž yt-dlp stderr:", result.stderr)

        if result.returncode == 0:
            files = glob.glob("/tmp/downloaded_audio.*")
            if files:
                print("โœ… yt-dlp success.")
                return files[0]

        # ๐Ÿ” Fallback: try pytube with cleaned URL
        print("๐Ÿ” yt-dlp failed. Trying pytube...")
        clean_url = clean_youtube_url(youtube_url)
        if not clean_url:
            raise ValueError("Unable to extract video ID for pytube fallback.")

        print(f"๐Ÿงฝ Cleaned URL for pytube: {clean_url}")
        yt = YouTube(clean_url)
        stream = yt.streams.filter(only_audio=True).first()
        if not stream:
            raise ValueError("No audio stream found via pytube.")

        output_path = "/tmp/fallback_audio.mp4"
        stream.download(filename=output_path)
        print("โœ… pytube download success.")
        return output_path

    except Exception as e:
        print("โŒ Final Download error:", e)
        raise RuntimeError(f"Download error: {e}")

def transcribe_audio(file_path):
    try:
        with open(file_path, "rb") as f:
            result = openai.audio.transcriptions.create(
                model="whisper-1",
                file=f,
                response_format="verbose_json"
            )
        return result["text"], result["language"]
    except Exception as e:
        raise RuntimeError(f"Transcription error: {e}")

def summarize_text(text, lang):
    lang = lang.lower()
    if lang.startswith("zh") or "chinese" in lang:
        prompt = "ไฝ ๆ˜ฏไธ€ไฝ่ฐๆ˜Ž็š„ๅŠฉๆ‰‹๏ผŒ่ƒฝๅค ็”จ็น้ซ”ไธญๆ–‡ๆธ…ๆฅšไธ”ๅฎŒๆ•ดๅœฐๆ‘˜่ฆๅฝฑ็‰‡ๅ…งๅฎนใ€‚"
    elif lang.startswith("ja") or "japanese" in lang:
        prompt = "ใ‚ใชใŸใฏๆ—ฅๆœฌ่ชžใง่ฆ็‚นใ‚’็ฐกๆฝ”ใ‹ใคๅˆ†ใ‹ใ‚Šใ‚„ใ™ใ่ฆ็ด„ใ™ใ‚‹ๆœ‰่ƒฝใชใ‚ขใ‚ทใ‚นใ‚ฟใƒณใƒˆใงใ™ใ€‚"
    else:
        prompt = "You are a helpful assistant that summarizes transcripts clearly and concisely."

    response = openai.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": prompt},
            {"role": "user", "content": f"Summarize the following transcript:\n\n{text}"}
        ]
    )

    summary = response.choices[0].message.content
    debug_info = f"๐ŸŒ Detected Language: {lang}\n๐Ÿง  Prompt Used: {prompt}"
    return summary, debug_info

def extract_video_id(url):
    match = re.search(r"(?:v=|shorts/)([a-zA-Z0-9_-]{11})", url)
    return match.group(1) if match else None

def full_process(youtube_url):
    try:
        video_id = extract_video_id(youtube_url)
        thumbnail_url = f"https://img.youtube.com/vi/{video_id}/maxresdefault.jpg" if video_id else None
        audio_path = download_audio(youtube_url)
        transcript, lang = transcribe_audio(audio_path)
        summary, debug = summarize_text(transcript, lang)
        return summary, debug, thumbnail_url
    except Exception as e:
        return f"โŒ Error: {str(e)}", "", None

with gr.Blocks() as demo:
    gr.Markdown("## ๐Ÿง  YouTube AI Summarizer\nEasily extract summaries from YouTube videos using Whisper + GPT. Supports English/Japanese/Chinese.")

    with gr.Row():
        youtube_input = gr.Textbox(label="๐ŸŽฅ Enter YouTube Video Link")
        submit_btn = gr.Button("๐Ÿ” Summarize")

    summary_output = gr.Textbox(label="๐Ÿ“ AI Video Summary", lines=6)
    info_output = gr.Textbox(label="๐Ÿ“„ Language & Model Info", lines=4)
    thumbnail_output = gr.Image(label="๐ŸŽž๏ธ Video Thumbnail", visible=True)

    submit_btn.click(fn=full_process, inputs=youtube_input, outputs=[summary_output, info_output, thumbnail_output])

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