From 3c44257d8a578a3fd447318965efa87b3851eb8a Mon Sep 17 00:00:00 2001 From: DataAnts-AI Date: Tue, 28 Jan 2025 17:00:03 -0500 Subject: [PATCH] Updated with code --- .gitignore | 4 +++ README.md | 25 ++++++++++++++++ app.py | 58 +++++++++++++++++++++++++++++++++++++ requirements.txt | 5 ++++ utils/audio_processing.py | 12 ++++++++ utils/summarization.py | 8 ++++++ utils/transcription.py | 60 +++++++++++++++++++++++++++++++++++++++ utils/validation.py | 8 ++++++ 8 files changed, 180 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app.py create mode 100644 requirements.txt create mode 100644 utils/audio_processing.py create mode 100644 utils/summarization.py create mode 100644 utils/transcription.py create mode 100644 utils/validation.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0eb8597 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +*.pyc +.env +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..147b56b --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# OBS Recording Transcriber + +Process OBS recordings with AI-based transcription and summarization. + + +## Features +- AI transcription using Whisper. +- Summarization using Hugging Face Transformers. +- File selection, resource validation, and error handling. + +## Installation +1. Clone the repo. +git clone https://github.com/yourusername/OBS_Recording_Transcriber.git +cd OBS_Recording_Transcriber +2. Install dependencies: + pip install -r requirements.txt + + +Notes: +Ensure that the versions align with the features you use and your system compatibility. +torch version should match the capabilities of your hardware (e.g., CUDA support for GPUs). +whisper might need to be installed from source or a GitHub repository if it's not available on PyPI. +If you encounter any issues regarding compatibility, versions may need adjustments. + +3. streamlit run app.py diff --git a/app.py b/app.py new file mode 100644 index 0000000..c138984 --- /dev/null +++ b/app.py @@ -0,0 +1,58 @@ +import streamlit as st +from utils.audio_processing import extract_audio +from utils.transcription import transcribe_audio +from utils.summarization import summarize_text +from utils.validation import validate_environment +from pathlib import Path + +def main(): + st.title("🎥 OBS Recording Transcriber") + st.caption("Process your OBS recordings with AI transcription and summarization") + + # Allow the user to select a base folder + st.sidebar.header("Folder Selection") + base_folder = st.sidebar.text_input( + "Enter the base folder path:", + value=str(Path.home()) + ) + + base_path = Path(base_folder) + + # Validate environment + env_errors = validate_environment(base_path) + if env_errors: + st.error("## Environment Issues") + for error in env_errors: + st.markdown(f"- {error}") + return + + # File selection + recordings = list(base_path.glob("*.mp4")) + if not recordings: + st.warning(f"📂 No recordings found in the folder: {base_folder}!") + return + + selected_file = st.selectbox("Choose a recording", recordings) + + if st.button("🚀 Start Processing"): + try: + transcript, summary = transcribe_audio(selected_file) + if transcript: + st.subheader("🖍 Summary") + st.write(summary) + st.subheader("📜 Full Transcript") + with st.expander("View transcript content"): + st.text(transcript) + st.download_button( + label="💾 Download Transcript", + data=transcript, + file_name=f"{Path(selected_file).stem}_transcript.txt", + mime="text/plain" + ) + else: + st.error("❌ Failed to process recording") + except Exception as e: + st.error(f"An error occurred: {e}") + st.write(e) # This will show the traceback in the Streamlit app +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..29da1a6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +streamlit==1.26.0 +moviepy==1.0.3 +whisper +transformers==4.21.1 +torch>=1.7.0 diff --git a/utils/audio_processing.py b/utils/audio_processing.py new file mode 100644 index 0000000..8256589 --- /dev/null +++ b/utils/audio_processing.py @@ -0,0 +1,12 @@ +from moviepy.editor import AudioFileClip +from pathlib import Path + +def extract_audio(video_path: Path): + """Extract audio from a video file.""" + try: + audio = AudioFileClip(str(video_path)) + audio_path = video_path.parent / f"{video_path.stem}_audio.wav" + audio.write_audiofile(str(audio_path), verbose=False, logger=None) + return audio_path + except Exception as e: + raise RuntimeError(f"Audio extraction failed: {e}") diff --git a/utils/summarization.py b/utils/summarization.py new file mode 100644 index 0000000..696d1c9 --- /dev/null +++ b/utils/summarization.py @@ -0,0 +1,8 @@ +from transformers import pipeline + +SUMMARY_MODEL = "Falconsai/text_summarization" + +def summarize_text(text): + """Summarize text using a Hugging Face pipeline.""" + summarizer = pipeline("summarization", model=SUMMARY_MODEL) + return summarizer(text, max_length=150, min_length=30, do_sample=False)[0]["summary_text"] diff --git a/utils/transcription.py b/utils/transcription.py new file mode 100644 index 0000000..4e737d2 --- /dev/null +++ b/utils/transcription.py @@ -0,0 +1,60 @@ +import whisper +from pathlib import Path +from transformers import pipeline, AutoTokenizer + +WHISPER_MODEL = "base" +SUMMARIZATION_MODEL = "t5-base" + +def transcribe_audio(audio_path: Path): + """Transcribe audio using Whisper.""" + model = whisper.load_model(WHISPER_MODEL) + result = model.transcribe(str(audio_path)) + transcript = result["text"] + summary = summarize_text(transcript) + return transcript, summary + +def summarize_text(text): + """Summarize text using a pre-trained T5 transformer model with chunking.""" + summarization_pipeline = pipeline("summarization", model=SUMMARIZATION_MODEL) + tokenizer = AutoTokenizer.from_pretrained(SUMMARIZATION_MODEL) + + max_tokens = 512 + + tokens = tokenizer(text, return_tensors='pt') + num_tokens = len(tokens['input_ids'][0]) + + if num_tokens > max_tokens: + chunks = chunk_text(text, max_tokens) + summaries = [] + for chunk in chunks: + summary_output = summarization_pipeline("summarize: " + chunk, max_length=150, min_length=30, do_sample=False) + summaries.append(summary_output[0]['summary_text']) + overall_summary = " ".join(summaries) + else: + overall_summary = summarization_pipeline("summarize: " + text, max_length=150, min_length=30, do_sample=False)[0]['summary_text'] + + return overall_summary + +def chunk_text(text, max_tokens): + """Splits the text into a list of chunks based on token limits.""" + tokenizer = AutoTokenizer.from_pretrained(SUMMARIZATION_MODEL) + words = text.split() + + chunks = [] + current_chunk = [] + current_length = 0 + + for word in words: + hypothetical_length = current_length + len(tokenizer(word, return_tensors='pt')['input_ids'][0]) - 2 + if hypothetical_length <= max_tokens: + current_chunk.append(word) + current_length = hypothetical_length + else: + chunks.append(' '.join(current_chunk)) + current_chunk = [word] + current_length = len(tokenizer(word, return_tensors='pt')['input_ids'][0]) - 2 + + if current_chunk: + chunks.append(' '.join(current_chunk)) + + return chunks \ No newline at end of file diff --git a/utils/validation.py b/utils/validation.py new file mode 100644 index 0000000..5079fd1 --- /dev/null +++ b/utils/validation.py @@ -0,0 +1,8 @@ +from pathlib import Path + +def validate_environment(obs_path: Path): + """Validate environment and prerequisites.""" + errors = [] + if not obs_path.exists(): + errors.append(f"OBS directory not found: {obs_path}") + return errors