ginipick commited on
Commit
94559cb
β€’
1 Parent(s): bb98d15

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +192 -40
app.py CHANGED
@@ -1,57 +1,209 @@
1
- import whisper
2
- from pytube import YouTube
3
  import gradio as gr
4
- import os
5
  import re
 
 
 
 
 
 
 
 
 
6
  import logging
7
 
 
8
  logging.basicConfig(level=logging.INFO)
 
 
9
  model = whisper.load_model("base")
10
 
11
- def get_text(url):
12
- #try:
13
- if url != '':
14
- output_text_transcribe = ''
15
 
16
- yt = YouTube(url)
17
- #video_length = yt.length --- doesn't work anymore - using byte file size of the audio file instead now
18
- #if video_length < 5400:
19
- video = yt.streams.filter(only_audio=True).first()
20
- out_file=video.download(output_path=".")
21
 
22
- file_stats = os.stat(out_file)
23
- logging.info(f'Size of audio file in Bytes: {file_stats.st_size}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- if file_stats.st_size <= 30000000:
26
- base, ext = os.path.splitext(out_file)
27
- new_file = base+'.mp3'
28
- os.rename(out_file, new_file)
29
- a = new_file
30
 
31
- result = model.transcribe(a)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  return result['text'].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  else:
34
- logging.error('Videos for transcription on this space are limited to about 1.5 hours. Sorry about this limit but some joker thought they could stop this tool from working by transcribing many extremely long videos. Please visit https://steve.digital to contact me about this space.')
35
- #finally:
36
- # raise gr.Error("Exception: There was a problem transcribing the audio.")
37
-
38
- def get_summary(article):
39
- first_sentences = ' '.join(re.split(r'(?<=[.:;])\s', article)[:5])
40
- b = summarizer(first_sentences, min_length = 20, max_length = 120, do_sample = False)
41
- b = b[0]['summary_text'].replace(' .', '.').strip()
42
- return b
43
-
44
- with gr.Blocks() as demo:
45
- gr.Markdown("<h1><center>YouTube URL Video-to-Text using <a href=https://openai.com/blog/whisper/ target=_blank>GPTube</a> Model</center></h1>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- input_text_url = gr.Textbox(placeholder='Youtube video URL', label='YouTube URL')
48
- result_button_transcribe = gr.Button('Transcribe')
49
- output_text_transcribe = gr.Textbox(placeholder='Transcript of the YouTube video.', label='Transcript')
 
 
 
 
50
 
51
- #result_button_summary = gr.Button('2. Create Summary')
52
- #output_text_summary = gr.Textbox(placeholder='Summary of the YouTube video transcript.', label='Summary')
 
53
 
54
- result_button_transcribe.click(get_text, inputs = input_text_url, outputs = output_text_transcribe)
55
- #result_button_summary.click(get_summary, inputs = output_text_transcribe, outputs = output_text_summary)
56
 
57
- demo.queue(default_enabled = True).launch(show_api=True)
 
 
 
 
1
  import gradio as gr
2
+ import requests
3
  import re
4
+ import os
5
+ import json
6
+ import time
7
+ import threading
8
+ from googleapiclient.discovery import build
9
+ from huggingface_hub import InferenceClient
10
+ from pytube import YouTube
11
+ import subprocess
12
+ import whisper
13
  import logging
14
 
15
+ # 둜그 μ„€μ •
16
  logging.basicConfig(level=logging.INFO)
17
+
18
+ # Whisper λͺ¨λΈ λ‘œλ“œ
19
  model = whisper.load_model("base")
20
 
21
+ # YouTube API ν‚€
22
+ API_KEY = 'AIzaSyDUz3wkGal0ewRtPlzeMit88bV4hS4ZIVY'
 
 
23
 
24
+ # YouTube API μ„œλΉ„μŠ€ λΉŒλ“œ
25
+ youtube = build('youtube', 'v3', developerKey=API_KEY)
 
 
 
26
 
27
+ # Hugging Face API μ„€μ •
28
+ client = InferenceClient(model="meta-llama/Meta-Llama-3-70B-Instruct", token=os.getenv("HF_TOKEN"))
29
+
30
+ WEBHOOK_URL = "https://connect.pabbly.com/workflow/sendwebhookdata/IjU3NjUwNTZhMDYzMDA0MzA1MjZhNTUzMzUxM2Ii_pc"
31
+ COMMENTS_FILE = 'comments.json'
32
+
33
+ DEFAULT_SYSTEM_PROMPT = "λŒ€ν™”μ‹œ λ°˜λ“œμ‹œ λ‚˜μ˜ 이름 'GPTube'λ₯Ό 밝히며 ν•œκΈ€λ‘œ 인사λ₯Όν•˜λΌ. λ°˜λ“œμ‹œ 'ν•œκΈ€'(ν•œκ΅­μ–΄)둜 250 토큰 μ΄λ‚΄λ‘œ 닡변을 μƒμ„±ν•˜κ³  좜λ ₯ν•˜λΌ. Respond to the following YouTube comment in a friendly and helpful manner:"
34
+
35
+ stop_event = threading.Event() # μŠ€λ ˆλ“œ 쀑지λ₯Ό μœ„ν•œ 이벀트
36
+
37
+ def load_existing_comments():
38
+ if os.path.exists(COMMENTS_FILE):
39
+ with open(COMMENTS_FILE, 'r') as file:
40
+ return json.load(file)
41
+ return []
42
+
43
+ def save_comments(comments):
44
+ with open(COMMENTS_FILE, 'w') as file:
45
+ json.dump(comments, file)
46
+
47
+ def download_audio(video_url):
48
+ yt = YouTube(video_url)
49
+ audio = yt.streams.filter(only_audio=True).first()
50
+ audio_path = audio.download(output_path=".")
51
 
52
+ file_stats = os.stat(audio_path)
53
+ logging.info(f'Size of audio file in Bytes: {file_stats.st_size}')
 
 
 
54
 
55
+ if file_stats.st_size <= 30000000: # Check the file size limit
56
+ base, ext = os.path.splitext(audio_path)
57
+ new_file = base + '.mp3'
58
+ os.rename(audio_path, new_file)
59
+ return new_file
60
+ else:
61
+ logging.error('Videos for transcription on this space are limited to about 1.5 hours. Please contact support for more information.')
62
+ return None
63
+
64
+ def generate_transcript(audio_path):
65
+ try:
66
+ if not audio_path or not os.path.exists(audio_path):
67
+ raise ValueError("μœ νš¨ν•œ μ˜€λ””μ˜€ 파일 κ²½λ‘œκ°€ μ•„λ‹™λ‹ˆλ‹€.")
68
+
69
+ result = model.transcribe(audio_path)
70
  return result['text'].strip()
71
+ except Exception as e:
72
+ logging.error(f"Exception during transcription: {str(e)}")
73
+ return f"전사 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}"
74
+
75
+ def generate_reply(comment_text, system_prompt):
76
+ prompt = f"{system_prompt}\n\nComment: {comment_text}\n\nReply:"
77
+ response = client.text_generation(
78
+ prompt=prompt,
79
+ max_new_tokens=250,
80
+ temperature=0.7,
81
+ top_p=0.9
82
+ )
83
+ if isinstance(response, dict) and 'generated_text' in response:
84
+ return response['generated_text']
85
+ return response
86
+
87
+ def send_webhook(data):
88
+ response = requests.post(WEBHOOK_URL, json=data)
89
+ return response.status_code, response.text
90
+
91
+ def get_video_comments(video_id):
92
+ try:
93
+ comments = []
94
+ request = youtube.commentThreads().list(
95
+ part='snippet',
96
+ videoId=video_id,
97
+ maxResults=100,
98
+ textFormat='plainText'
99
+ )
100
+ response = request.execute()
101
+ while request is not None:
102
+ for item in response['items']:
103
+ snippet = item['snippet']['topLevelComment']['snippet']
104
+ comment = {
105
+ 'comment_id': item['snippet']['topLevelComment']['id'],
106
+ 'author': snippet['authorDisplayName'],
107
+ 'published_at': snippet['publishedAt'],
108
+ 'text': snippet['textDisplay'],
109
+ 'reply_count': item['snippet']['totalReplyCount']
110
+ }
111
+ comments.append(comment)
112
+ if 'nextPageToken' in response:
113
+ request = youtube.commentThreads().list(
114
+ part='snippet',
115
+ videoId=video_id,
116
+ pageToken=response['nextPageToken'],
117
+ maxResults=100,
118
+ textFormat='plainText'
119
+ )
120
+ response = request.execute()
121
+ else:
122
+ break
123
+ return comments
124
+ except Exception as e:
125
+ return [{'error': str(e)}]
126
+
127
+ def fetch_comments(video_url, system_prompt):
128
+ log_entries = []
129
+ video_id_match = re.search(r'(?:v=|\/)([0-9A-Za-z_-]{11}).*', video_url)
130
+ if video_id_match:
131
+ video_id = video_id_match.group(1)
132
+ audio_path = download_audio(video_url)
133
+ if not audio_path:
134
+ return "μ˜€λ””μ˜€λ₯Ό λ‹€μš΄λ‘œλ“œν•  수 μ—†μŠ΅λ‹ˆλ‹€."
135
+
136
+ transcript = generate_transcript(audio_path)
137
+
138
+ existing_comments = load_existing_comments()
139
+ new_comments = get_video_comments(video_id)
140
+
141
+ if not new_comments or 'error' in new_comments[0]]:
142
+ return "λŒ“κΈ€μ„ 찾을 수 μ—†κ±°λ‚˜ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."
143
+
144
+ recent_new_comments = [c for c in new_comments if c['comment_id'] not in {c['comment_id'] for c in existing_comments} and c['reply_count'] == 0]
145
+
146
+ if recent_new_comments:
147
+ for most_recent_comment in recent_new_comments:
148
+ combined_prompt = f"{transcript}\n\n{system_prompt}"
149
+ reply_text = generate_reply(most_recent_comment['text'], combined_prompt)
150
+ webhook_data = {
151
+ "comment_id": most_recent_comment['comment_id'],
152
+ "author": most_recent_comment['author'],
153
+ "published_at": most_recent_comment['published_at'],
154
+ "text": most_recent_comment['text'],
155
+ "reply_text": reply_text
156
+ }
157
+ webhook_status, webhook_response = send_webhook(webhook_data)
158
+ log_entries.append(f"졜근 λŒ“κΈ€: {most_recent_comment['text']}\n\nλ‹΅λ³€ 생성: {reply_text}\n\nμ›Ήν›… 응닡: {webhook_status} - {webhook_response}")
159
+ existing_comments.append(most_recent_comment)
160
+ save_comments(existing_comments)
161
+ else:
162
+ log_entries.append("μƒˆλ‘œμš΄ λŒ“κΈ€μ΄ μ—†μŠ΅λ‹ˆλ‹€.")
163
  else:
164
+ log_entries.append("μœ νš¨ν•˜μ§€ μ•Šμ€ YouTube URLμž…λ‹ˆλ‹€.")
165
+ return "\n\n".join(log_entries)
166
+
167
+ def background_fetch_comments():
168
+ while not stop_event.is_set():
169
+ result = fetch_comments("https://www.youtube.com/watch?v=dQw4w9WgXcQ", DEFAULT_SYSTEM_PROMPT) # URLκ³Ό ν”„λ‘¬ν”„νŠΈ μ‹€μ œ μ‚¬μš© μ˜ˆμ‹œ
170
+ print(result)
171
+ time.sleep(10)
172
+
173
+ def start_background_fetch():
174
+ threading.Thread(target=background_fetch_comments).start()
175
+
176
+ def stop_background_fetch():
177
+ stop_event.set()
178
+
179
+ def get_text(video_url):
180
+ audio_path = download_audio(video_url)
181
+ if not audio_path:
182
+ return "μ˜€λ””μ˜€λ₯Ό λ‹€μš΄λ‘œλ“œν•  수 μ—†μŠ΅λ‹ˆλ‹€."
183
+
184
+ transcript = generate_transcript(audio_path)
185
+ return transcript
186
+
187
+ # Gradio μΈν„°νŽ˜μ΄μŠ€ μ •μ˜
188
+ demo = gr.Blocks()
189
+
190
+ with demo:
191
+ gr.Markdown("<h1><center>YouTube URL Video-to-Text using <a href=https://openai.com/blog/whisper/ target=_blank>Whisper</a> Model</center></h1>")
192
 
193
+ with gr.Row():
194
+ input_text_url = gr.Textbox(placeholder='YouTube video URL', label='YouTube URL')
195
+ input_text_prompt = gr.Textbox(placeholder='μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ', label='μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ', value=DEFAULT_SYSTEM_PROMPT, lines=5)
196
+
197
+ with gr.Row():
198
+ result_button_transcribe = gr.Button('Transcribe')
199
+ result_button_comments = gr.Button('Fetch Comments and Generate Reply')
200
 
201
+ with gr.Row():
202
+ output_text_transcribe = gr.Textbox(placeholder='Transcript of the YouTube video.', label='Transcript', lines=20)
203
+ output_text_prompt = gr.Textbox(placeholder='응닡 ν…μŠ€νŠΈ', label='응닡 ν…μŠ€νŠΈ', lines=20)
204
 
205
+ result_button_transcribe.click(get_text, inputs=input_text_url, outputs=output_text_transcribe, api_name="transcribe_api")
206
+ result_button_comments.click(fetch_comments, inputs=[input_text_url, input_text_prompt], outputs=output_text_prompt, api_name="fetch_comments_api")
207
 
208
+ # μΈν„°νŽ˜μ΄μŠ€ μ‹€ν–‰
209
+ demo.launch()