agnixcode commited on
Commit
bcdefd2
·
verified ·
1 Parent(s): 7462c22

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -27
app.py CHANGED
@@ -3,6 +3,7 @@ import re
3
  import gradio as gr
4
  import numpy as np
5
  import faiss
 
6
  from youtube_transcript_api import YouTubeTranscriptApi
7
  from sentence_transformers import SentenceTransformer
8
  from langchain_text_splitters import RecursiveCharacterTextSplitter
@@ -12,7 +13,7 @@ from groq import Groq
12
  # CONFIG & INITIALIZATION
13
  # ===============================
14
 
15
- # Get API Key from Environment Variables (Set this in HF Settings)
16
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
17
  groq_client = Groq(api_key=GROQ_API_KEY) if GROQ_API_KEY else None
18
 
@@ -28,21 +29,27 @@ chunks_store = []
28
  # ===============================
29
 
30
  def extract_video_id(url):
31
- """Extracts the 11-character YouTube video ID."""
32
- regex = r"(?:v=|\/)([0-9A-Za-z_-]{11}).*"
33
  match = re.search(regex, url)
34
  if match:
35
  return match.group(1)
36
  return None
37
 
38
  def get_transcript(url):
 
 
 
39
  try:
40
  video_id = extract_video_id(url)
41
  if not video_id:
42
- return "ERROR: Invalid YouTube URL."
43
 
44
- transcript_data = YouTubeTranscriptApi.get_transcript(video_id)
45
- full_text = " ".join([item['text'] for item in transcript_data])
 
 
 
46
  return full_text
47
  except Exception as e:
48
  return f"ERROR: Could not retrieve transcript. (Details: {str(e)})"
@@ -50,32 +57,53 @@ def get_transcript(url):
50
  def process_transcript(transcript):
51
  global vector_store, chunks_store
52
 
 
53
  splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=60)
54
  chunks = splitter.split_text(transcript)
55
 
 
56
  embeddings = embedding_model.encode(chunks)
 
 
57
  dimension = embeddings.shape[1]
58
  index = faiss.IndexFlatL2(dimension)
59
  index.add(np.array(embeddings).astype('float32'))
60
 
 
61
  vector_store = index
62
  chunks_store = chunks
63
 
64
  def retrieve_context(query, top_k=3):
 
 
 
65
  query_embedding = embedding_model.encode([query])
66
  distances, indices = vector_store.search(np.array(query_embedding).astype('float32'), top_k)
 
 
67
  retrieved_chunks = [chunks_store[i] for i in indices[0] if i != -1]
68
  return "\n\n".join(retrieved_chunks)
69
 
70
  def generate_answer(query):
71
  if not groq_client:
72
- return "API Key not configured. Please add GROQ_API_KEY to Space Secrets."
73
 
74
  context = retrieve_context(query)
75
- prompt = f"""You are a helpful AI assistant. Use ONLY the context below to answer.
76
- Context: {context}
77
- Question: {query}
78
- Answer:"""
 
 
 
 
 
 
 
 
 
 
 
79
 
80
  response = groq_client.chat.completions.create(
81
  model="llama-3.3-70b-versatile",
@@ -84,23 +112,27 @@ def generate_answer(query):
84
  return response.choices[0].message.content
85
 
86
  # ===============================
87
- # GRADIO PIPELINE FUNCTIONS
88
  # ===============================
89
 
90
  def process_video_ui(url):
91
  if not url:
92
- return "Please enter a URL", "❌ No URL provided"
93
 
94
  transcript = get_transcript(url)
 
95
  if transcript.startswith("ERROR"):
96
- return transcript, "❌ Failed"
97
 
98
  process_transcript(transcript)
99
- return transcript[:1000] + "...", "✅ Video processed! Start chatting."
100
 
101
  def chat_with_video_ui(user_query, history):
 
 
 
102
  if vector_store is None:
103
- history.append((user_query, "⚠️ Please process a video in the first tab first."))
104
  return history, ""
105
 
106
  answer = generate_answer(user_query)
@@ -108,28 +140,28 @@ def chat_with_video_ui(user_query, history):
108
  return history, ""
109
 
110
  # ===============================
111
- # GRADIO UI DESIGN
112
  # ===============================
113
 
114
  with gr.Blocks(theme=gr.themes.Soft()) as app:
115
- gr.Markdown("# 🎥 YouTube RAG: Chat with any Video")
116
- gr.Markdown("Paste a YouTube link to transcribe it, then ask questions about the content using Llama 3.3 via Groq.")
117
 
118
  with gr.Tabs():
119
- with gr.Tab("1. Process Video"):
120
- url_input = gr.Textbox(label="YouTube URL", placeholder="https://www.youtube.com/watch?v=...")
121
- process_btn = gr.Button("Transcribe & Index", variant="primary")
122
  with gr.Row():
123
  status_output = gr.Textbox(label="Status")
124
- transcript_preview = gr.Textbox(label="Transcript Preview (First 1000 chars)", lines=5)
125
 
126
  process_btn.click(process_video_ui, inputs=url_input, outputs=[transcript_preview, status_output])
127
 
128
- with gr.Tab("2. Chat"):
129
- chatbot = gr.Chatbot(height=450)
130
  with gr.Row():
131
- msg = gr.Textbox(label="Ask a question...", placeholder="What is this video about?", scale=4)
132
- submit = gr.Button("Send", variant="primary", scale=1)
133
 
134
  submit.click(chat_with_video_ui, inputs=[msg, chatbot], outputs=[chatbot, msg])
135
  msg.submit(chat_with_video_ui, inputs=[msg, chatbot], outputs=[chatbot, msg])
 
3
  import gradio as gr
4
  import numpy as np
5
  import faiss
6
+ # Import the library
7
  from youtube_transcript_api import YouTubeTranscriptApi
8
  from sentence_transformers import SentenceTransformer
9
  from langchain_text_splitters import RecursiveCharacterTextSplitter
 
13
  # CONFIG & INITIALIZATION
14
  # ===============================
15
 
16
+ # Get API Key from Environment Variables (Set this in HF Space Secrets)
17
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
18
  groq_client = Groq(api_key=GROQ_API_KEY) if GROQ_API_KEY else None
19
 
 
29
  # ===============================
30
 
31
  def extract_video_id(url):
32
+ """Extracts the 11-character YouTube video ID from various URL formats."""
33
+ regex = r"(?:v=|\/|be\/)([0-9A-Za-z_-]{11}).*"
34
  match = re.search(regex, url)
35
  if match:
36
  return match.group(1)
37
  return None
38
 
39
  def get_transcript(url):
40
+ """
41
+ Fetch transcript using the correct static method.
42
+ """
43
  try:
44
  video_id = extract_video_id(url)
45
  if not video_id:
46
+ return "ERROR: Invalid YouTube URL. Could not find Video ID."
47
 
48
+ # FIX: Calling the static method directly on the class
49
+ # We also try to fetch English by default or the first available
50
+ transcript_list = YouTubeTranscriptApi.get_transcript(video_id)
51
+
52
+ full_text = " ".join([item['text'] for item in transcript_list])
53
  return full_text
54
  except Exception as e:
55
  return f"ERROR: Could not retrieve transcript. (Details: {str(e)})"
 
57
  def process_transcript(transcript):
58
  global vector_store, chunks_store
59
 
60
+ # Split text into manageable chunks
61
  splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=60)
62
  chunks = splitter.split_text(transcript)
63
 
64
+ # Create embeddings
65
  embeddings = embedding_model.encode(chunks)
66
+
67
+ # Initialize FAISS Index
68
  dimension = embeddings.shape[1]
69
  index = faiss.IndexFlatL2(dimension)
70
  index.add(np.array(embeddings).astype('float32'))
71
 
72
+ # Store globally for retrieval
73
  vector_store = index
74
  chunks_store = chunks
75
 
76
  def retrieve_context(query, top_k=3):
77
+ if vector_store is None:
78
+ return ""
79
+
80
  query_embedding = embedding_model.encode([query])
81
  distances, indices = vector_store.search(np.array(query_embedding).astype('float32'), top_k)
82
+
83
+ # Fetch matching chunks
84
  retrieved_chunks = [chunks_store[i] for i in indices[0] if i != -1]
85
  return "\n\n".join(retrieved_chunks)
86
 
87
  def generate_answer(query):
88
  if not groq_client:
89
+ return "Error: Groq API Key is not set in Hugging Face Secrets."
90
 
91
  context = retrieve_context(query)
92
+ if not context:
93
+ return "I don't have any context from the video yet. Please process a video first."
94
+
95
+ prompt = f"""
96
+ You are a professional AI Assistant. Use the provided context from a YouTube video to answer the user's question.
97
+ If the answer isn't in the context, say you don't know based on the video.
98
+
99
+ Context:
100
+ {context}
101
+
102
+ Question:
103
+ {query}
104
+
105
+ Answer:
106
+ """
107
 
108
  response = groq_client.chat.completions.create(
109
  model="llama-3.3-70b-versatile",
 
112
  return response.choices[0].message.content
113
 
114
  # ===============================
115
+ # UI LOGIC
116
  # ===============================
117
 
118
  def process_video_ui(url):
119
  if not url:
120
+ return "Please enter a valid URL", "❌ No URL"
121
 
122
  transcript = get_transcript(url)
123
+
124
  if transcript.startswith("ERROR"):
125
+ return transcript, "❌ Failed to fetch transcript"
126
 
127
  process_transcript(transcript)
128
+ return transcript[:1500] + "...", "✅ Video processed! You can now chat."
129
 
130
  def chat_with_video_ui(user_query, history):
131
+ if not user_query:
132
+ return history, ""
133
+
134
  if vector_store is None:
135
+ history.append((user_query, "⚠️ Please process a video in the first tab before chatting."))
136
  return history, ""
137
 
138
  answer = generate_answer(user_query)
 
140
  return history, ""
141
 
142
  # ===============================
143
+ # GRADIO INTERFACE
144
  # ===============================
145
 
146
  with gr.Blocks(theme=gr.themes.Soft()) as app:
147
+ gr.Markdown("# 🎥 YouTube RAG AI Expert")
148
+ gr.Markdown("Transcribe any YouTube video and chat with its content using Llama 3.3 & FAISS.")
149
 
150
  with gr.Tabs():
151
+ with gr.Tab("1. Load Video"):
152
+ url_input = gr.Textbox(label="YouTube Link", placeholder="https://www.youtube.com/watch?v=...")
153
+ process_btn = gr.Button("Transcribe & Index Video", variant="primary")
154
  with gr.Row():
155
  status_output = gr.Textbox(label="Status")
156
+ transcript_preview = gr.Textbox(label="Transcript Preview", lines=8)
157
 
158
  process_btn.click(process_video_ui, inputs=url_input, outputs=[transcript_preview, status_output])
159
 
160
+ with gr.Tab("2. Chat with AI"):
161
+ chatbot = gr.Chatbot(height=500)
162
  with gr.Row():
163
+ msg = gr.Textbox(label="Your Question", placeholder="What are the key takeaways?", scale=4)
164
+ submit = gr.Button("Ask", variant="primary", scale=1)
165
 
166
  submit.click(chat_with_video_ui, inputs=[msg, chatbot], outputs=[chatbot, msg])
167
  msg.submit(chat_with_video_ui, inputs=[msg, chatbot], outputs=[chatbot, msg])