Mubin1917 commited on
Commit
dd41bc7
1 Parent(s): 6a369e2

Update Jul 25

Browse files
Files changed (2) hide show
  1. FC_tool_main.py +103 -196
  2. app.py +1 -3
FC_tool_main.py CHANGED
@@ -7,26 +7,22 @@ the LangChain library for natural language processing tasks and the YouTube Tran
7
  API for fetching video transcripts.
8
 
9
  Classes:
10
- MainPointsExtractor:
11
- Extracts and formats main points from YouTube video transcripts.
12
- Timestamps are formatted for direct use in YouTube comments, enabling clickable
13
- links to specific video sections when pasted.
14
- SummaryExtractor:
15
- Handles the extraction and formatting of video summaries.
16
  QuestionAnswerExtractor:
17
  Processes user questions and extracts answers from video transcripts.
18
  YouTubeAgent:
19
  Manages the overall agent setup for interacting with YouTube videos and processing user queries.
20
 
21
  Key Features:
22
- - Main points summarization in multiple formats
23
- - Video content summarization
24
  - Question answering based on video content
25
  - Flexible AI agent for handling various YouTube video-related tasks
26
  """
27
 
28
  import os
29
  import openai
 
30
  from typing import List, Dict, Any, Union, Type
31
  from youtube_transcript_api import YouTubeTranscriptApi
32
  from langchain_core.pydantic_v1 import BaseModel, Field
@@ -40,7 +36,6 @@ from langchain_core.utils.function_calling import convert_to_openai_function
40
  from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
41
  from langchain.agents.format_scratchpad import format_to_openai_functions
42
  from langchain.memory import ConversationBufferWindowMemory
43
- from dotenv import load_dotenv, find_dotenv
44
 
45
  # _ = load_dotenv(find_dotenv()) # read local .env file
46
  openai.api_key = os.getenv('OPENAI_API_KEY') #os.environ['OPENAI_API_KEY']
@@ -55,59 +50,63 @@ def set_temperature(new_temperature):
55
  get_temperature = new_get_temperature
56
  # print(f"Temperature set to: {get_temperature()}")
57
 
58
- class Points_1(BaseModel):
59
  """Pydantic model for representing extracted points from Youtube-Transcript"""
60
- timestamp: float = Field(description="The timestamp (in floating-point number) of when main points are discussed or talked about in the video.")
61
  main_point: str = Field(description="A title for Main point.")
62
- summary: str = Field(description="A summary of main points discussed at that timestamp. End with fullstop.")
63
  emoji: str = Field(description="An emoji that matches the summary.")
64
-
65
- class Points_2(BaseModel):
66
  """Pydantic model for representing extracted points."""
67
  main_point: str = Field(description="The main topic, theme, or subject extracted from the subtitle.")
 
68
  summary: str = Field(description="The context or brief explanation of the main point.")
69
  emoji: str = Field(description="An emoji that represents or summarizes the main point.")
70
- timestamp: float = Field(description="The timestamp (in floating-point number) from the video where the main point is mentioned.")
71
-
72
- class MainPointsExtractor:
73
  """
74
- A tool for extracting and formatting main points from YouTube video transcripts.
75
 
76
- This class provides methods to process transcripts and identify key points
77
- using natural language processing techniques.
78
  """
79
 
80
- class Info_1(BaseModel):
81
- """Pydantic model for representing a collection of points."""
82
- points: List[Points_1]
83
 
84
- class Info_2(BaseModel):
85
- """Pydantic model for representing a collection of points."""
86
- points: List[Points_2]
87
 
88
  @staticmethod
89
  @tool(return_direct=True)
90
- def get_youtube_video_main_points(youtube_video_id: str) -> str:
91
  """
92
- Extracts and formats main points with Timestamps from YouTube video transcripts. Timestamps are formatted for direct use in YouTube comments, enabling clickable links to specific video sections when pasted.
93
 
94
  Args:
95
  youtube_video_id (str): The ID of the YouTube video.
96
 
97
  Returns:
98
- str: Formatted string of main points extracted from the video.
99
  """
100
  try:
101
- transcript = MainPointsExtractor._get_youtube_video_transcript(youtube_video_id)
102
- main_points_1 = MainPointsExtractor._extract_main_points(transcript, MainPointsExtractor.Info_1)
103
- main_points_2 = MainPointsExtractor._extract_main_points(transcript, MainPointsExtractor.Info_2)
104
- formatted_output = f"""Main points extracted from YouTube video (ID: {youtube_video_id})\nStyle_1:\n```\n{main_points_2}\n```\nStyle_2:\n```\n{main_points_1}\n```\nChoose the style that best suits your needs for presenting the main points of the video."""
105
- return formatted_output
 
 
 
 
106
  except Exception as e:
107
  raise
108
 
109
  @staticmethod
110
- def _get_youtube_video_transcript(youtube_video_id: str) -> str:
111
  """
112
  Fetches the transcript for a YouTube video.
113
 
@@ -128,12 +127,12 @@ class MainPointsExtractor:
128
  raise
129
 
130
  @staticmethod
131
- def _extract_main_points(transcript: str, info_model: Union[Type[Info_1], Type[Info_2]]) -> List[Dict[str, Any]]:
132
  """
133
  Extracts main points from the transcript using NLP techniques.
134
 
135
  This method maintains a conversation history to provide context for subsequent calls.
136
-
137
  Args:
138
  transcript (str): The full transcript of the video.
139
 
@@ -143,22 +142,19 @@ class MainPointsExtractor:
143
  main_points_extraction_function = [convert_to_openai_function(info_model)]
144
 
145
  model = ChatOpenAI(temperature=get_temperature())
146
-
147
- extraction_model = model.bind(functions=main_points_extraction_function)
148
 
149
  system_message = f"""
150
- You are an AI assistant that extracts info from video transcripts.
151
- When extracting info, ensure that:
152
- 1. Each point has a unique timestamp.
 
 
 
 
 
153
 
154
- In addition to these specific requirements, you have the authority to make other improvements as you see fit. This may include:
155
-
156
- - Refining the summaries for clarity and conciseness
157
- - Adjusting emoji choices to better represent the content
158
- - Reorganizing points for better logical flow
159
- - Removing redundant information
160
- - Adding context where necessary
161
-
162
  Your goal is to produce a refined and accurate representation of the main points from the video transcript. Use your judgment to balance adherence to the specific rules with overall improvement of the extracted information.
163
  """
164
 
@@ -169,11 +165,11 @@ class MainPointsExtractor:
169
 
170
  extraction_chain = prompt | extraction_model | JsonKeyOutputFunctionsParser(key_name="points")
171
 
172
- text_splitter = RecursiveCharacterTextSplitter(chunk_overlap=0, chunk_size=8192, separators=[f" {char}" for char in "123456789"])
173
 
174
  prep = RunnableLambda(lambda x: [{"input": doc} for doc in text_splitter.split_text(x)])
175
 
176
- chain = prep | extraction_chain.map() | MainPointsExtractor._flatten | MainPointsExtractor._format_youtube_comment
177
 
178
  result_1 = chain.invoke(transcript)
179
 
@@ -183,17 +179,19 @@ class MainPointsExtractor:
183
  def _flatten(matrix):
184
  """Flattens a 2D list into a 1D list."""
185
  return [item for row in matrix for item in row]
186
-
187
  @staticmethod
188
- def _format_youtube_comment(json_data: List[Dict[str, Any]]) -> str:
189
  """
190
- Formats extracted main points into a YouTube-style comment.
191
 
192
  Args:
193
- json_data (List[Dict[str, Any]]): List of dictionaries containing main points.
 
 
194
 
195
  Returns:
196
- str: Formatted string representing the main points as a YouTube comment.
197
  """
198
  def _format_timestamp(seconds):
199
  hours = int(seconds // 3600)
@@ -202,125 +200,24 @@ class MainPointsExtractor:
202
  return f"{hours:02}:{minutes:02}:{seconds:02}"
203
 
204
  formatted_comment = ""
205
- for entry in json_data:
206
- timestamp = _format_timestamp(entry['timestamp'])
207
- emoji = entry['emoji']
208
- summary = entry['summary']
209
 
210
- if entry['main_point'].endswith('.'):
211
- point = entry['main_point'][:-1]
 
 
212
  else:
213
- point = entry['main_point']
214
-
215
- formatted_comment += f"{timestamp} {emoji} {point}: {summary}\n"
216
 
217
  return formatted_comment.strip()
218
-
219
- #######################################################################################################################################
220
-
221
- class Summary(BaseModel):
222
- """Pydantic model for representing extracted summary."""
223
- summary: str = Field(description="Extract detailed information from the content.")
224
-
225
- class SummaryExtractor:
226
- """
227
- A tool for extracting and formatting summaries from YouTube video transcripts.
228
-
229
- This class provides methods to process transcripts and generate concise summaries
230
- using natural language processing techniques.
231
- """
232
-
233
- class Info(BaseModel):
234
- """Pydantic model for representing a collection of summaries."""
235
- summary: List[Summary]
236
-
237
- @staticmethod
238
- @tool(return_direct=False)
239
- def get_youtube_video_summary(youtube_video_id: str) -> str:
240
- """
241
- Extracts and formats a summary from a YouTube video transcript.
242
-
243
- Args:
244
- youtube_video_id (str): The ID of the YouTube video.
245
-
246
- Returns:
247
- str: Formatted string of the summary extracted from the video.
248
- """
249
- try:
250
- transcript = SummaryExtractor._get_youtube_video_transcript(youtube_video_id)
251
- summary = SummaryExtractor._extract_summary(transcript)
252
- return SummaryExtractor._format_summary(summary)
253
- except Exception as e:
254
- return f"Error extracting summary: {str(e)}"
255
-
256
- @staticmethod
257
- def _get_youtube_video_transcript(youtube_video_id: str) -> str:
258
- """
259
- Fetches the transcript for a YouTube video.
260
-
261
- Args:
262
- youtube_video_id (str): The ID of the YouTube video.
263
-
264
- Returns:
265
- str: The full transcript of the video.
266
-
267
- Raises:
268
- Exception: If there's an error fetching the transcript.
269
- """
270
- try:
271
- transcript_json = YouTubeTranscriptApi.get_transcript(youtube_video_id)
272
- transcript_data = [entry['text'] for entry in transcript_json]
273
- return " ".join(transcript_data)
274
- except Exception as e:
275
- raise
276
-
277
- @staticmethod
278
- def _extract_summary(transcript: str) -> List[Summary]:
279
- """
280
- Extracts a summary from a YouTube video transcript.
281
-
282
- Args:
283
- transcript (str): The full transcript of the video.
284
-
285
- Returns:
286
- Summary: A Summary object containing the extracted summary.
287
- """
288
- summary_extraction_function = [convert_to_openai_function(SummaryExtractor.Info)]
289
-
290
- model = ChatOpenAI(temperature=get_temperature())
291
-
292
- extraction_model = model.bind(functions=summary_extraction_function)
293
-
294
- prompt = ChatPromptTemplate.from_messages([("human", "{input}")])
295
-
296
- extraction_chain = prompt | extraction_model | JsonKeyOutputFunctionsParser(key_name="summary")
297
-
298
- text_splitter = RecursiveCharacterTextSplitter(chunk_overlap=0, chunk_size=8192, separators=[f" {char}" for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"])
299
-
300
- prep = RunnableLambda(lambda x: [{"input": doc} for doc in text_splitter.split_text(x)])
301
-
302
- chain = prep | extraction_chain.map() | MainPointsExtractor._flatten
303
-
304
- return chain.invoke(transcript)
305
-
306
- @staticmethod
307
- def _format_summary(summaries: List[Summary]) -> str:
308
- """
309
- Formats the list of summaries into a single string.
310
- Args:
311
- summaries (List[Summary]): List of Summary objects.
312
- Returns:
313
- str: A formatted string containing all summaries.
314
- """
315
- return "\n\n".join([s["summary"] for s in summaries])
316
-
317
- #############################################################################################################################################################
318
 
319
  class Answer(BaseModel):
320
  """Pydantic model for representing an answer to a question."""
321
  answer: str = Field(description="The answer to the user's question based on the video transcript.")
322
  confidence: float = Field(description="A confidence score between 0 and 1 indicating how certain the model is about the answer.")
323
-
324
  class QuestionAnswerExtractor:
325
  """
326
  A tool for answering questions about YouTube videos based on their transcripts.
@@ -349,7 +246,7 @@ class QuestionAnswerExtractor:
349
  try:
350
  transcript = QuestionAnswerExtractor._get_youtube_video_transcript(youtube_video_id)
351
  answer = QuestionAnswerExtractor._extract_answer(transcript, question)
352
- return QuestionAnswerExtractor._format_answer(answer)
353
  except Exception as e:
354
  return f"Error answering question: {str(e)}"
355
 
@@ -384,7 +281,7 @@ class QuestionAnswerExtractor:
384
  question (str): The user's question about the video.
385
 
386
  Returns:
387
- List[Answer]: A list of Answer objects containing the extracted answers.
388
  """
389
  answer_extraction_function = [convert_to_openai_function(QuestionAnswerExtractor.Info)]
390
 
@@ -408,34 +305,37 @@ class QuestionAnswerExtractor:
408
 
409
  chain = prep | extraction_chain.map() | QuestionAnswerExtractor._flatten
410
 
411
- return chain.invoke({"transcript": transcript, "question": question})
 
412
 
413
- @staticmethod
414
- def _flatten(matrix):
415
- """Flattens a 2D list into a 1D list."""
416
- return [item for row in matrix for item in row]
417
 
418
- @staticmethod
419
- def _format_answer(answers: List[Answer]) -> str:
420
- """
421
- Formats the list of answers into a single string.
422
 
423
- Args:
424
- answers (List[Answer]): List of Answer objects.
425
-
426
- Returns:
427
- str: A formatted string containing the best answer and its confidence score.
428
- """
429
- if not answers:
430
- return "I couldn't find an answer to your question based on the video transcript."
431
 
432
- # Sort answers by confidence score and take the best one
433
- best_answer = max(answers, key=lambda x: x['confidence'])
434
 
435
- return f"{best_answer['answer']}({best_answer['confidence']:.2f})"
436
-
437
- #######################################################################################################################################
438
-
 
 
 
 
 
 
 
 
439
  class YouTubeAgent:
440
  """
441
  An agent for interacting with YouTube videos and processing user queries.
@@ -448,12 +348,19 @@ class YouTubeAgent:
448
  """Initializes the YouTubeAgent with necessary tools and components."""
449
 
450
  self.tools = [
451
- MainPointsExtractor.get_youtube_video_main_points,
452
- SummaryExtractor.get_youtube_video_summary,
453
- QuestionAnswerExtractor.get_answer
454
  ]
455
 
456
- self.sys_message = "You are a helpful assistant."
 
 
 
 
 
 
 
 
457
 
458
  self.functions = [convert_to_openai_function(f) for f in self.tools]
459
 
 
7
  API for fetching video transcripts.
8
 
9
  Classes:
10
+ YouTubeTranscriptPointsExtractor:
11
+ Extracts and formats comments with clickable timestamps from a YouTube video transcript.
 
 
 
 
12
  QuestionAnswerExtractor:
13
  Processes user questions and extracts answers from video transcripts.
14
  YouTubeAgent:
15
  Manages the overall agent setup for interacting with YouTube videos and processing user queries.
16
 
17
  Key Features:
18
+ - Main points formatted as youtube comment with clickable timestamps
 
19
  - Question answering based on video content
20
  - Flexible AI agent for handling various YouTube video-related tasks
21
  """
22
 
23
  import os
24
  import openai
25
+ import json
26
  from typing import List, Dict, Any, Union, Type
27
  from youtube_transcript_api import YouTubeTranscriptApi
28
  from langchain_core.pydantic_v1 import BaseModel, Field
 
36
  from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
37
  from langchain.agents.format_scratchpad import format_to_openai_functions
38
  from langchain.memory import ConversationBufferWindowMemory
 
39
 
40
  # _ = load_dotenv(find_dotenv()) # read local .env file
41
  openai.api_key = os.getenv('OPENAI_API_KEY') #os.environ['OPENAI_API_KEY']
 
50
  get_temperature = new_get_temperature
51
  # print(f"Temperature set to: {get_temperature()}")
52
 
53
+ class TimestampedPoint_1(BaseModel):
54
  """Pydantic model for representing extracted points from Youtube-Transcript"""
55
+ timestamp: float = Field(description="The timestamp (in floating-point number) of when main points are discussed in the video.")
56
  main_point: str = Field(description="A title for Main point.")
57
+ summary: str = Field(description="A summary of main points discussed at that timestamp.")
58
  emoji: str = Field(description="An emoji that matches the summary.")
59
+
60
+ class TimestampedPoint_2(BaseModel):
61
  """Pydantic model for representing extracted points."""
62
  main_point: str = Field(description="The main topic, theme, or subject extracted from the subtitle.")
63
+ timestamp: float = Field(description="The timestamp (in floating-point number) from the video where the main point is mentioned.")
64
  summary: str = Field(description="The context or brief explanation of the main point.")
65
  emoji: str = Field(description="An emoji that represents or summarizes the main point.")
66
+
67
+ class YouTubeTranscriptPointsExtractor:
 
68
  """
69
+ A tool for extracting and formatting main points with clickable timestamps from YouTube video transcripts.
70
 
71
+ This class provides methods to process transcripts, identify key points,
72
+ and format them for use in YouTube comments with clickable timestamps.
73
  """
74
 
75
+ class PointsCollection_1(BaseModel):
76
+ """Pydantic model for representing a collection of timestamped points."""
77
+ points: List[TimestampedPoint_1]
78
 
79
+ class PointsCollection_2(BaseModel):
80
+ """Pydantic model for representing a collection of timestamped points."""
81
+ points: List[TimestampedPoint_2]
82
 
83
  @staticmethod
84
  @tool(return_direct=True)
85
+ def extract_clickable_points(youtube_video_id: str) -> str:
86
  """
87
+ Extracts and formats comments with clickable timestamps from a YouTube video transcript.
88
 
89
  Args:
90
  youtube_video_id (str): The ID of the YouTube video.
91
 
92
  Returns:
93
+ str: Formatted string of main points with clickable timestamps, ready for use in YouTube comments.
94
  """
95
  try:
96
+ transcript = YouTubeTranscriptPointsExtractor._fetch_transcript(youtube_video_id)
97
+ extracted_points_1 = YouTubeTranscriptPointsExtractor._process_transcript(transcript, YouTubeTranscriptPointsExtractor.PointsCollection_1)
98
+ formatted_output_1 = YouTubeTranscriptPointsExtractor._format_for_youtube_comment(extracted_points_1, True)
99
+ formatted_output_1a = YouTubeTranscriptPointsExtractor._format_for_youtube_comment(extracted_points_1, False)
100
+
101
+ extracted_points_2 = YouTubeTranscriptPointsExtractor._process_transcript(transcript, YouTubeTranscriptPointsExtractor.PointsCollection_2)
102
+ formatted_output_2 = YouTubeTranscriptPointsExtractor._format_for_youtube_comment(extracted_points_2, True)
103
+ formatted_output_2a = YouTubeTranscriptPointsExtractor._format_for_youtube_comment(extracted_points_2, False)
104
+ return f"""Main points extracted from YouTube video (ID: {youtube_video_id})\nOutput_style_1:\n```\n{formatted_output_1}\n```\nOutput_Style_1a:\n```\n{formatted_output_1a}\n```\nOutput_Style_2a:\n```\n{formatted_output_2}\n```\nOutput_Style_2a:\n```\n{formatted_output_2a}\n```\nChoose the style that best suits your needs for presenting the main points of the video."""
105
  except Exception as e:
106
  raise
107
 
108
  @staticmethod
109
+ def _fetch_transcript(youtube_video_id: str) -> str:
110
  """
111
  Fetches the transcript for a YouTube video.
112
 
 
127
  raise
128
 
129
  @staticmethod
130
+ def _process_transcript(transcript: str, info_model: Union[Type[PointsCollection_1], Type[PointsCollection_2]]) -> List[Dict[str, Any]]:
131
  """
132
  Extracts main points from the transcript using NLP techniques.
133
 
134
  This method maintains a conversation history to provide context for subsequent calls.
135
+
136
  Args:
137
  transcript (str): The full transcript of the video.
138
 
 
142
  main_points_extraction_function = [convert_to_openai_function(info_model)]
143
 
144
  model = ChatOpenAI(temperature=get_temperature())
145
+
146
+ extraction_model = model.bind(functions=main_points_extraction_function, function_call={"name": info_model.__name__})
147
 
148
  system_message = f"""
149
+ You are an AI assistant that extracts essential info from video transcripts.
150
+ You have the authority to make improvements as you see fit.
151
+
152
+ Rules To Follow:
153
+ - Refining the summaries for clarity and conciseness.
154
+ - Adjusting emoji choices to better represent the content.
155
+ - Removing redundant information.
156
+ - Grouping two points into a single point if the timestamps are close enough.
157
 
 
 
 
 
 
 
 
 
158
  Your goal is to produce a refined and accurate representation of the main points from the video transcript. Use your judgment to balance adherence to the specific rules with overall improvement of the extracted information.
159
  """
160
 
 
165
 
166
  extraction_chain = prompt | extraction_model | JsonKeyOutputFunctionsParser(key_name="points")
167
 
168
+ text_splitter = RecursiveCharacterTextSplitter(chunk_overlap=0, chunk_size=16000, separators=[f" {char}" for char in "123456789"])
169
 
170
  prep = RunnableLambda(lambda x: [{"input": doc} for doc in text_splitter.split_text(x)])
171
 
172
+ chain = prep | extraction_chain.map() | YouTubeTranscriptPointsExtractor._flatten
173
 
174
  result_1 = chain.invoke(transcript)
175
 
 
179
  def _flatten(matrix):
180
  """Flattens a 2D list into a 1D list."""
181
  return [item for row in matrix for item in row]
182
+
183
  @staticmethod
184
+ def _format_for_youtube_comment(points: List[Dict[str, Any]], detailed: bool = True) -> str:
185
  """
186
+ Formats extracted main points into a YouTube-style comment with clickable timestamps.
187
 
188
  Args:
189
+ points (List[Dict[str, Any]]): List of dictionaries containing main points with timestamps.
190
+ detailed (bool): If True, returns a detailed format with emojis and summaries.
191
+ If False, returns a simpler format with just timestamps and main points.
192
 
193
  Returns:
194
+ str: Formatted string representing the main points as a YouTube comment with clickable timestamps.
195
  """
196
  def _format_timestamp(seconds):
197
  hours = int(seconds // 3600)
 
200
  return f"{hours:02}:{minutes:02}:{seconds:02}"
201
 
202
  formatted_comment = ""
203
+ for point in points:
204
+ timestamp = _format_timestamp(point['timestamp'])
205
+ main_point = point['main_point'].rstrip('.')
 
206
 
207
+ if detailed:
208
+ emoji = point['emoji']
209
+ summary = point['summary']
210
+ formatted_comment += f"{timestamp} {emoji} {main_point}: {summary}\n"
211
  else:
212
+ formatted_comment += f"{timestamp} {main_point}\n"
 
 
213
 
214
  return formatted_comment.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
  class Answer(BaseModel):
217
  """Pydantic model for representing an answer to a question."""
218
  answer: str = Field(description="The answer to the user's question based on the video transcript.")
219
  confidence: float = Field(description="A confidence score between 0 and 1 indicating how certain the model is about the answer.")
220
+
221
  class QuestionAnswerExtractor:
222
  """
223
  A tool for answering questions about YouTube videos based on their transcripts.
 
246
  try:
247
  transcript = QuestionAnswerExtractor._get_youtube_video_transcript(youtube_video_id)
248
  answer = QuestionAnswerExtractor._extract_answer(transcript, question)
249
+ return answer
250
  except Exception as e:
251
  return f"Error answering question: {str(e)}"
252
 
 
281
  question (str): The user's question about the video.
282
 
283
  Returns:
284
+ List[Answer]: A list containing a single Answer object with the consolidated answer.
285
  """
286
  answer_extraction_function = [convert_to_openai_function(QuestionAnswerExtractor.Info)]
287
 
 
305
 
306
  chain = prep | extraction_chain.map() | QuestionAnswerExtractor._flatten
307
 
308
+ # Get partial answers
309
+ partial_answers = chain.invoke({"transcript": transcript, "question": question})
310
 
311
+ # Filter out low-confidence answers
312
+ filtered_answers = [answer for answer in partial_answers if answer['confidence'] > 0.4]
 
 
313
 
314
+ # If all answers were filtered out, return a low-confidence "no answer" response
315
+ if not filtered_answers:
316
+ return "I couldn't find a reliable answer to your question based on the video transcript."
 
317
 
318
+ # Consolidate filtered partial answers
319
+ consolidation_prompt = ChatPromptTemplate.from_messages([
320
+ ("system", "You are an AI assistant tasked with consolidating multiple partial answers into a comprehensive final answer."),
321
+ ("human", "Question: {question}\n\nPartial Answers: {partial_answers}\n\nPlease provide a consolidated, comprehensive answer to the question based on these partial answers. Ignore any information from answers with low confidence (0.5 or below).")
322
+ ])
 
 
 
323
 
324
+ consolidation_model = ChatOpenAI(temperature=get_temperature())
325
+ consolidation_chain = consolidation_prompt | consolidation_model
326
 
327
+ final_answer = consolidation_chain.invoke({
328
+ "question": question,
329
+ "partial_answers": json.dumps(filtered_answers, indent=2)
330
+ })
331
+
332
+ return final_answer.content
333
+
334
+ @staticmethod
335
+ def _flatten(matrix):
336
+ """Flattens a 2D list into a 1D list."""
337
+ return [item for row in matrix for item in row]
338
+
339
  class YouTubeAgent:
340
  """
341
  An agent for interacting with YouTube videos and processing user queries.
 
348
  """Initializes the YouTubeAgent with necessary tools and components."""
349
 
350
  self.tools = [
351
+ QuestionAnswerExtractor.get_answer,
352
+ YouTubeTranscriptPointsExtractor.extract_clickable_points,
 
353
  ]
354
 
355
+ self.sys_message = """You are a helpful assistant specialized in processing YouTube video transcripts and answering questions about video content.'
356
+
357
+ Important instructions:
358
+ 1. Only use the 'extract_clickable_points' tool when the user explicitly asks for clickable points or timestamps from a video.
359
+ 2. For all other queries, including general questions about video content, use the 'get_answer' tool.
360
+ 3. If the user's query is unclear, ask for clarification before using any tools.
361
+ 4. Always provide concise and relevant responses based on the tool outputs.
362
+
363
+ Remember to interpret the user's intent carefully and use the appropriate tool for each situation."""
364
 
365
  self.functions = [convert_to_openai_function(f) for f in self.tools]
366
 
app.py CHANGED
@@ -66,10 +66,8 @@ with gr.Blocks() as demo:
66
  API for fetching video transcripts.
67
 
68
  Key Features:
69
- - Main points summarization in multiple formats
70
- - Video content summarization
71
  - Question answering based on video content
72
- - Flexible AI agent for handling various YouTube video-related tasks
73
 
74
  Simply enter your question or request along with a YouTube video link, and the AI will process and respond accordingly.
75
  Adjust the temperature slider to control the creativity of the AI's responses.
 
66
  API for fetching video transcripts.
67
 
68
  Key Features:
69
+ - Main points formatted as youtube comment with clickable timestamps
 
70
  - Question answering based on video content
 
71
 
72
  Simply enter your question or request along with a YouTube video link, and the AI will process and respond accordingly.
73
  Adjust the temperature slider to control the creativity of the AI's responses.