ginipick commited on
Commit
94559cb
·
verified ·
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()