From 3b55ee561a52264ee223178e458dde8564f9edcb Mon Sep 17 00:00:00 2001 From: tylerreed Date: Fri, 7 Jun 2024 16:25:41 -0400 Subject: [PATCH] added classes to make it easier --- .../youtube-summarizer/AudioTranscriber.py | 37 ++++++++++ .../youtube-summarizer/AutoGenInteraction.py | 52 +++++++++++++ .../YouTubeAudioDownloader.py | 29 ++++++++ _integrations/youtube-summarizer/main.py | 32 ++++++++ _integrations/youtube-summarizer/youtube.py | 74 ------------------- 5 files changed, 150 insertions(+), 74 deletions(-) create mode 100644 _integrations/youtube-summarizer/AudioTranscriber.py create mode 100644 _integrations/youtube-summarizer/AutoGenInteraction.py create mode 100644 _integrations/youtube-summarizer/YouTubeAudioDownloader.py create mode 100644 _integrations/youtube-summarizer/main.py delete mode 100644 _integrations/youtube-summarizer/youtube.py diff --git a/_integrations/youtube-summarizer/AudioTranscriber.py b/_integrations/youtube-summarizer/AudioTranscriber.py new file mode 100644 index 0000000..4b37572 --- /dev/null +++ b/_integrations/youtube-summarizer/AudioTranscriber.py @@ -0,0 +1,37 @@ +import io +import time +from pydub import AudioSegment +import openai + + +class AudioTranscriber: + def __init__(self, api_key, model='whisper-1', chunk_duration=20): + self.client = openai.OpenAI(api_key=api_key) + self.model = model + self.chunk_duration_ms = chunk_duration * 60 * 1000 + + def transcribe_audio(self, filename): + audio = AudioSegment.from_file(filename) + transcription = "" + for split_number, i in enumerate(range(0, len(audio), self.chunk_duration_ms)): + chunk = audio[i: i + self.chunk_duration_ms] + file_obj = io.BytesIO(chunk.export(format="mp3").read()) + file_obj.name = f"part_{split_number}.mp3" + transcription += self.transcribe_chunk(file_obj, split_number) + return transcription + + def transcribe_chunk(self, file_obj, split_number): + print(f"Transcribing part {split_number + 1}!") + attempts = 0 + while attempts < 3: + try: + transcript = self.client.audio.transcriptions.create( + model=self.model, file=file_obj + ) + return transcript.text + except Exception as e: + attempts += 1 + print(f"Attempt {attempts} failed. Exception: {str(e)}") + time.sleep(5) + print("Failed to transcribe after 3 attempts.") + return "" diff --git a/_integrations/youtube-summarizer/AutoGenInteraction.py b/_integrations/youtube-summarizer/AutoGenInteraction.py new file mode 100644 index 0000000..0d4140f --- /dev/null +++ b/_integrations/youtube-summarizer/AutoGenInteraction.py @@ -0,0 +1,52 @@ +import autogen + + +class AutoGenInteraction: + def __init__(self, api_key, transcription): + self.llm_config = { + "config_list": [{ + "model": "gpt-3.5-turbo", + "api_key": api_key + }], + "temperature": 0, + "cache_seed": None + } + self.transcription = transcription + + def initiate_chat(self): + user = autogen.UserProxyAgent( + "user", + system_message="You are an administrator.", + human_input_mode="NEVER", + is_termination_msg=lambda msg: "TERMINATE" in msg["content"], + code_execution_config=False, + ) + + agent_summarizer = autogen.AssistantAgent( + "agent_summarizer", + system_message="You are an assistant agent. When you are done, reply with TERMINATE", + llm_config=self.llm_config + ) + + agent_translator = autogen.AssistantAgent( + "ai_agent_translator", + system_message="You are an assistant agent. When you are done, reply with TERMINATE", + llm_config=self.llm_config + ) + + user.initiate_chats( + [ + { + "recipient": agent_summarizer, + "message": f"Can you summarize: {self.transcription} this nicely with the title and then bullet points?", + "clear_history": True, + "silent": False, + "summary_method": "last_msg", + }, + { + "recipient": agent_translator, + "message": "Can you translate this into Dutch?", + "summary_method": "last_msg", + }, + ] + ) diff --git a/_integrations/youtube-summarizer/YouTubeAudioDownloader.py b/_integrations/youtube-summarizer/YouTubeAudioDownloader.py new file mode 100644 index 0000000..a39558b --- /dev/null +++ b/_integrations/youtube-summarizer/YouTubeAudioDownloader.py @@ -0,0 +1,29 @@ +import yt_dlp +import os + + +class YouTubeAudioDownloader: + def __init__(self, url, output_template='%(title)s [%(id)s].%(ext)s'): + self.url = url + self.ydl_opts = { + 'format': 'bestaudio/best', + 'outtmpl': output_template, + 'postprocessors': [{ + 'key': 'FFmpegExtractAudio', + 'preferredcodec': 'm4a', + }] + } + + def download_audio(self): + with yt_dlp.YoutubeDL(self.ydl_opts) as ydl: + info_dict = ydl.extract_info(self.url, download=True) + filename = ydl.prepare_filename(info_dict) + return self.find_file_in_directory(filename) + + @staticmethod + def find_file_in_directory(base_filename): + base_name, _ = os.path.splitext(base_filename) + for file in os.listdir('.'): + if file.startswith(base_name): + return file + raise FileNotFoundError(f"The file {base_filename} does not exist in the current directory.") diff --git a/_integrations/youtube-summarizer/main.py b/_integrations/youtube-summarizer/main.py new file mode 100644 index 0000000..2d22511 --- /dev/null +++ b/_integrations/youtube-summarizer/main.py @@ -0,0 +1,32 @@ +import os +from dotenv import load_dotenv + +from YouTubeAudioDownloader import YouTubeAudioDownloader +from AudioTranscriber import AudioTranscriber +from AutoGenInteraction import AutoGenInteraction + +load_dotenv() + + +def main(): + url = 'https://www.youtube.com/watch?v=WqIzUopTPvU' + openai_api_key = os.getenv("OPENAI_API_KEY") + + # gives you the filename from yt video + downloader = YouTubeAudioDownloader(url) + filename = downloader.download_audio() + print(f"Downloaded and saved audio (m4a) as: {filename}") + + # transcribes the audio + transcriber = AudioTranscriber(api_key=openai_api_key) + transcription = transcriber.transcribe_audio(filename) + print("Transcription completed.") + + # ai agents summarize/translate + autogen_interaction = AutoGenInteraction(api_key=openai_api_key, transcription=transcription) + autogen_interaction.initiate_chat() + print("Chat completed.") + + +if __name__ == "__main__": + main() diff --git a/_integrations/youtube-summarizer/youtube.py b/_integrations/youtube-summarizer/youtube.py deleted file mode 100644 index 7dc3198..0000000 --- a/_integrations/youtube-summarizer/youtube.py +++ /dev/null @@ -1,74 +0,0 @@ -import yt_dlp -import os -import io -import time -from dotenv import load_dotenv -from langchain_community.document_loaders.blob_loaders.youtube_audio import ( - YoutubeAudioLoader, -) -from langchain_community.document_loaders.generic import GenericLoader -from langchain_community.document_loaders.parsers import ( - OpenAIWhisperParser, -) -from pydub import AudioSegment - -import openai - -load_dotenv() - -URLS = ['https://www.youtube.com/watch?v=LQRuaP2VFfA'] - -ydl_opts = { - 'format': 'm4a/bestaudio/best', - # ℹ️ See help(yt_dlp.postprocessor) for a list of available Postprocessors and their arguments - 'postprocessors': [{ # Extract audio using ffmpeg - 'key': 'FFmpegExtractAudio', - 'preferredcodec': 'm4a', - }] -} - -with yt_dlp.YoutubeDL(ydl_opts) as ydl: - ydl.download(URLS) - -client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) -# openai.api_key = os.getenv("OPENAI_API_KEY") - -# Audio file from disk -audio = AudioSegment.from_file("./test.m4a") - -# Define the duration of each chunk in minutes -# Need to meet 25MB size limit for Whisper API -chunk_duration = 20 -chunk_duration_ms = chunk_duration * 60 * 1000 - -# Split the audio into chunk_duration_ms chunks -for split_number, i in enumerate(range(0, len(audio), chunk_duration_ms)): - # Audio chunk - chunk = audio[i: i + chunk_duration_ms] - # Skip chunks that are too short to transcribe - # if chunk.duration_seconds <= self.chunk_duration_threshold: - # continue - file_obj = io.BytesIO(chunk.export(format="mp3").read()) - # if blob.source is not None: - # file_obj.name = blob.source + f"_part_{split_number}.mp3" - # else: - file_obj.name = f"part_{split_number}.mp3" - - # Transcribe - print(f"Transcribing part {split_number + 1}!") # noqa: T201 - attempts = 0 - while attempts < 3: - try: - transcript = client.audio.transcriptions.create( - model="whisper-1", file=file_obj - ) - break - except Exception as e: - attempts += 1 - print(f"Attempt {attempts} failed. Exception: {str(e)}") # noqa: T201 - time.sleep(5) - else: - print("Failed to transcribe after 3 attempts.") # noqa: T201 - continue - - print(transcript.text)