From 69625569feaa329526aa7e751e5f435878d6edd5 Mon Sep 17 00:00:00 2001 From: tcsenpai Date: Tue, 19 Nov 2024 22:57:45 +0100 Subject: [PATCH] Modernized UI + share function added --- env.example | 3 +- src/main.py | 255 +++++++++++++++++++++++++++++++---------- src/pastebin_client.py | 26 +++++ 3 files changed, 221 insertions(+), 63 deletions(-) create mode 100644 src/pastebin_client.py diff --git a/env.example b/env.example index d54cc1f..57a0aa7 100644 --- a/env.example +++ b/env.example @@ -2,4 +2,5 @@ OLLAMA_URL=http://localhost:11434 OLLAMA_MODEL=llama3.1:8b YOUTUBE_API_KEY=your_youtube_api_key WHISPER_URL=http://localhost:8000/ -WHISPER_MODEL=Systran/faster-whisper-large-v3 \ No newline at end of file +WHISPER_MODEL=Systran/faster-whisper-large-v3 +PASTEBIN_API_KEY=your_pastebin_api_key \ No newline at end of file diff --git a/src/main.py b/src/main.py index 62711db..2c17f28 100644 --- a/src/main.py +++ b/src/main.py @@ -7,6 +7,8 @@ from ollama_client import OllamaClient from video_info import get_video_info from yt_audiophile import download_audio from whisper_module import transcribe +from pastebin_client import create_paste +from pathlib import Path # Load environment variables load_dotenv() @@ -17,48 +19,108 @@ st.set_page_config( page_icon="src/assets/subtitles.png", ) -# Custom CSS for the banner +# Add this after set_page_config st.markdown( """ - """, +""", unsafe_allow_html=True, ) -# Banner with icon and title -st.markdown( - """ - - """, - unsafe_allow_html=True, -) +# Initialize session state for messages if not exists +if "messages" not in st.session_state: + st.session_state.messages = [] -# Initialize Rich console +# Create a single header container +header = st.container() + +def show_warning(message): + update_header("⚠️ " + message) + +def show_error(message): + update_header("🚫 " + message) + +def show_info(message): + update_header("✅ " + message) + +def update_header(message): + with header: + st.markdown( + f""" +
+ {message} +
+ + """, + unsafe_allow_html=True, + ) + +# Initialize the header with a ready message +update_header("✅ Ready to summarize!") + +# Add spacing after the fixed header +# st.markdown("
", unsafe_allow_html=True) def get_transcript(video_id): @@ -101,11 +163,11 @@ def summarize_video( with st.spinner("Fetching transcript..."): transcript = get_transcript(video_id) - st.success("Summarizer fetched successfully!") + show_info("Summarizer fetched successfully!") # Forcing whisper if specified if force_whisper: - st.warning("Forcing whisper...") + show_warning("Forcing whisper...") fallback_to_whisper = True transcript = None @@ -115,38 +177,42 @@ def summarize_video( print("Fallback to whisper is disabled") return "Unable to fetch transcript (and fallback to whisper is disabled)" if not force_whisper: - print("Force whisper is disabled") - st.warning("Unable to fetch transcript. Trying to download audio...") + show_warning("Unable to fetch transcript. Trying to download audio...") try: print("Downloading audio...") download_audio(video_url) - st.success("Audio downloaded successfully!") - st.warning("Starting transcription...it might take a while...") + show_info("Audio downloaded successfully!") + show_warning("Starting transcription...it might take a while...") transcript = transcribe("downloads/output.m4a") - st.success("Transcription completed successfully!") + show_info("Transcription completed successfully!") os.remove("downloads/output.m4a") except Exception as e: print(f"Error downloading audio or transcribing: {e}") - st.error(f"Error downloading audio or transcribing: {e}") + show_error(f"Error downloading audio or transcribing: {e}") if os.path.exists("downloads/output.m4a"): os.remove("downloads/output.m4a") return "Unable to fetch transcript." print(f"Transcript: {transcript}") ollama_client = OllamaClient(ollama_url, model) - st.success(f"Ollama client created with model: {model}") + show_info(f"Ollama client created with model: {model}") - st.warning("Starting summary generation, this might take a while...") + show_warning("Starting summary generation, this might take a while...") with st.spinner("Generating summary..."): prompt = f"Summarize the following YouTube video transcript in a concise yet detailed manner:\n\n```{transcript}```\n\nSummary with introduction and conclusion formatted in markdown:" summary = ollama_client.generate(prompt) print(summary) - st.success("Summary generated successfully!") + show_info("Summary generated successfully!") with st.spinner("Fetching video info..."): video_info = get_video_info(video_id) st.success("Video info fetched successfully!") - return f"Title: {video_info['title']}\n\nChannel: {video_info['channel']}\n\nSummary:\n{summary}" + return { + "title": video_info["title"], + "channel": video_info["channel"], + "transcript": transcript, + "summary": summary, + } def main(): @@ -186,24 +252,55 @@ def main(): st.caption(f"Whisper model: {whisper_model}") # Create model selection dropdown - selected_model = st.selectbox( - "Select Ollama Model", - options=available_models, - index=( - available_models.index(default_model) - if default_model in available_models - else 0 - ), - ) + # selected_model = st.selectbox( + # "Select Ollama Model", + # options=available_models, + # index=( + # available_models.index(default_model) + # if default_model in available_models + # else 0 + # ), + # ) - video_url = st.text_input("Enter the YouTube video URL:") - - # Add checkboxes for whisper options - col1, col2 = st.columns(2) + # Use columns for URL and model inputs + col1, col2 = st.columns([2, 1]) with col1: - force_whisper = st.checkbox("Force Whisper", value=False) + video_url = st.text_input( + "Enter the YouTube video URL:", + placeholder="https://www.youtube.com/watch?v=...", + ) with col2: - fallback_to_whisper = st.checkbox("Fallback to Whisper", value=True) + selected_model = st.selectbox( + "Select Ollama Model", + options=available_models, + index=( + available_models.index(default_model) + if default_model in available_models + else 0 + ), + ) + + # Group Ollama and Whisper settings + with st.expander("Advanced Settings"): + col1, col2 = st.columns(2) + with col1: + ollama_url = st.text_input( + "Ollama URL", + value=default_ollama_url, + placeholder="Enter custom Ollama URL", + ) + with col2: + whisper_url = st.text_input( + "Whisper URL", + value=default_whisper_url, + placeholder="Enter custom Whisper URL", + ) + + col1, col2 = st.columns(2) + with col1: + force_whisper = st.checkbox("Force Whisper", value=False) + with col2: + fallback_to_whisper = st.checkbox("Fallback to Whisper", value=True) # Support any video that has a valid YouTube ID if not "https://www.youtube.com/watch?v=" or "https://youtu.be/" in video_url: @@ -226,8 +323,42 @@ def main(): fallback_to_whisper=fallback_to_whisper, force_whisper=force_whisper, ) + st.subheader("Video Information:") + st.write(f"**Title:** {summary['title']}") + st.write(f"**Channel:** {summary['channel']}") + st.subheader("Summary:") - st.write(summary) + st.write(summary["summary"]) + + st.subheader("Original Transcript:") + st.text_area( + "Full Transcript", summary["transcript"], height=300, disabled=True + ) + + # Share button moved here, after the transcript + if st.button("Share Transcript"): + try: + content = f"""Video Title: {summary['title']} +Channel: {summary['channel']} +URL: {video_url} + +--- Transcript --- + +{summary['transcript']}""" + + paste_url = create_paste( + f"Transcript: {summary['title']}", content + ) + st.success( + f"Transcript shared successfully! [View here]({paste_url})" + ) + except Exception as e: + if "PASTEBIN_API_KEY" not in os.environ: + st.warning( + "PASTEBIN_API_KEY not found in environment variables" + ) + else: + st.error(f"Error sharing transcript: {str(e)}") else: st.error("Please enter a valid YouTube video URL.") diff --git a/src/pastebin_client.py b/src/pastebin_client.py new file mode 100644 index 0000000..111917b --- /dev/null +++ b/src/pastebin_client.py @@ -0,0 +1,26 @@ +import requests +import os +from dotenv import load_dotenv + +load_dotenv() + +def create_paste(title, content): + api_key = os.getenv("PASTEBIN_API_KEY") + if not api_key: + raise Exception("PASTEBIN_API_KEY not found in environment variables") + + url = 'https://pastebin.com/api/api_post.php' + data = { + 'api_dev_key': api_key, + 'api_option': 'paste', + 'api_paste_code': content, + 'api_paste_private': '0', # 0=public, 1=unlisted, 2=private + 'api_paste_name': title, + 'api_paste_expire_date': '1W' # Expires in 1 week + } + + response = requests.post(url, data=data) + if response.status_code == 200 and not response.text.startswith('Bad API request'): + return response.text + else: + raise Exception(f"Error creating paste: {response.text}") \ No newline at end of file