EtienneB commited on
Commit
e43f584
·
1 Parent(s): 61cae63
Files changed (5) hide show
  1. __pycache__/tools.cpython-313.pyc +0 -0
  2. agent.py +4 -3
  3. app.py +30 -8
  4. requirements.txt +19 -3
  5. tools.py +81 -1
__pycache__/tools.cpython-313.pyc CHANGED
Binary files a/__pycache__/tools.cpython-313.pyc and b/__pycache__/tools.cpython-313.pyc differ
 
agent.py CHANGED
@@ -14,8 +14,9 @@ from tools import (absolute, add, analyze_csv_file, analyze_excel_file,
14
  factorial, floor_divide, get_current_time_in_timezone,
15
  greatest_common_divisor, is_prime, least_common_multiple,
16
  logarithm, modulus, multiply, percentage_calculator, power,
17
- python_code_parser, roman_calculator_converter, square_root,
18
- subtract, web_search, wiki_search)
 
19
 
20
  # Load Constants
21
  load_dotenv()
@@ -31,7 +32,7 @@ tools = [
31
  is_prime, least_common_multiple, percentage_calculator,
32
  wiki_search, analyze_excel_file, arvix_search,
33
  audio_transcription, python_code_parser, analyze_csv_file,
34
- extract_text
35
  ]
36
 
37
  # Load system prompt
 
14
  factorial, floor_divide, get_current_time_in_timezone,
15
  greatest_common_divisor, is_prime, least_common_multiple,
16
  logarithm, modulus, multiply, percentage_calculator, power,
17
+ python_code_parser, reverse_sentence,
18
+ roman_calculator_converter, square_root, subtract,
19
+ web_search, wiki_search)
20
 
21
  # Load Constants
22
  load_dotenv()
 
32
  is_prime, least_common_multiple, percentage_calculator,
33
  wiki_search, analyze_excel_file, arvix_search,
34
  audio_transcription, python_code_parser, analyze_csv_file,
35
+ extract_text, reverse_sentence
36
  ]
37
 
38
  # Load system prompt
app.py CHANGED
@@ -16,24 +16,46 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
16
  # --- Basic Agent Definition ---
17
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
18
  class BasicAgent:
 
 
 
 
 
 
 
 
 
19
  def __init__(self):
 
20
  print("BasicAgent initialized.")
 
 
21
  self.graph = build_graph()
22
 
23
  def __call__(self, question: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
24
  print(f"Agent received question (first 50 chars): {question[:50]}...")
25
  # Wrap the question in a HumanMessage from langchain_core
26
  messages = [HumanMessage(content=question)]
27
- messages = self.graph.invoke({"messages": messages})
28
- answer = messages['messages'][-1].content
 
 
 
29
  print(f"Agent full response: {answer}")
 
30
 
31
- # Optionally trim the "Final Answer: " prefix only if it exists
32
- if answer.startswith("Final Answer:"):
33
- return answer[len("Final Answer:"):].strip()
34
- else:
35
- return answer.strip()
36
-
37
 
38
 
39
  def run_and_submit_all( profile: gr.OAuthProfile | None):
 
16
  # --- Basic Agent Definition ---
17
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
18
  class BasicAgent:
19
+ """A basic agent that uses a pre-built graph to answer questions.
20
+
21
+ This agent is initialized with a graph structure that defines its
22
+ reasoning and processing flow. When called, it takes a user's question,
23
+ invokes the graph with it, and returns the final response.
24
+
25
+ Attributes:
26
+ graph: The compiled graph from `build_graph()` that processes messages.
27
+ """
28
  def __init__(self):
29
+ """Initializes the BasicAgent by building its processing graph."""
30
  print("BasicAgent initialized.")
31
+ # This function should be defined elsewhere in the code.
32
+ # It is expected to return a compiled LangChain graph.
33
  self.graph = build_graph()
34
 
35
  def __call__(self, question: str) -> str:
36
+ """Processes a question using the agent's graph and returns the answer.
37
+
38
+ This method makes the agent instance callable. It wraps the user's
39
+ question in a HumanMessage, sends it through the processing graph,
40
+ and extracts the content from the final message in the response.
41
+
42
+ Args:
43
+ question: The question to be processed by the agent.
44
+
45
+ Returns:
46
+ The answer generated by the agent's graph as a string.
47
+ """
48
  print(f"Agent received question (first 50 chars): {question[:50]}...")
49
  # Wrap the question in a HumanMessage from langchain_core
50
  messages = [HumanMessage(content=question)]
51
+ # The graph.invoke method takes a dictionary with the key "messages"
52
+ # and returns a dictionary with the processed messages.
53
+ response_messages = self.graph.invoke({"messages": messages})
54
+ # The answer is expected to be in the 'content' of the last message.
55
+ answer = response_messages['messages'][-1].content
56
  print(f"Agent full response: {answer}")
57
+ return answer
58
 
 
 
 
 
 
 
59
 
60
 
61
  def run_and_submit_all( profile: gr.OAuthProfile | None):
requirements.txt CHANGED
@@ -35,6 +35,22 @@ assemblyai # For AssemblyAIAudioTranscriptLoader
35
 
36
  # Additional utilities
37
  typing-extensions
38
- asyncio-throttle
39
- tenacity
40
- loguru
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  # Additional utilities
37
  typing-extensions
38
+ # asyncio-throttle
39
+ #tenacity
40
+ # loguru
41
+
42
+ torch
43
+ torchvision
44
+ opencv-python
45
+ pytube
46
+
47
+ # YOLOv5 and dependencies
48
+ numpy
49
+ matplotlib
50
+ scipy
51
+ seaborn
52
+ tqdm
53
+ pyyaml
54
+ pillow
55
+
56
+ git+https://github.com/ultralytics/yolov5.git
tools.py CHANGED
@@ -2,10 +2,13 @@ import base64
2
  import datetime
3
  import math
4
  import os
5
- from typing import List, Union
 
6
 
 
7
  import pandas
8
  import pytz
 
9
  from langchain.schema import HumanMessage
10
  from langchain_community.document_loaders import (
11
  ArxivLoader, AssemblyAIAudioTranscriptLoader, WikipediaLoader)
@@ -14,6 +17,7 @@ from langchain_community.document_loaders.parsers import LanguageParser
14
  from langchain_community.tools import DuckDuckGoSearchRun
15
  from langchain_core.tools import tool
16
  from langchain_google_genai import ChatGoogleGenerativeAI
 
17
 
18
 
19
  @tool
@@ -748,3 +752,79 @@ def extract_text(img_path: str) -> str:
748
  error_msg = f"Error extracting text: {str(e)}"
749
  print(error_msg)
750
  return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import datetime
3
  import math
4
  import os
5
+ import tempfile
6
+ from typing import Dict, Union
7
 
8
+ import cv2
9
  import pandas
10
  import pytz
11
+ import torch
12
  from langchain.schema import HumanMessage
13
  from langchain_community.document_loaders import (
14
  ArxivLoader, AssemblyAIAudioTranscriptLoader, WikipediaLoader)
 
17
  from langchain_community.tools import DuckDuckGoSearchRun
18
  from langchain_core.tools import tool
19
  from langchain_google_genai import ChatGoogleGenerativeAI
20
+ from pytube import YouTube
21
 
22
 
23
  @tool
 
752
  error_msg = f"Error extracting text: {str(e)}"
753
  print(error_msg)
754
  return ""
755
+
756
+
757
+ @tool
758
+ def reverse_sentence(text: str) -> str:
759
+ """
760
+ Reverses the input text.
761
+ Args:
762
+ text (str): The input string to be reversed.
763
+ Returns:
764
+ str: The reversed string.
765
+ """
766
+ return text[::-1]
767
+
768
+
769
+ def get_max_bird_species_count_from_video(url: str) -> Dict:
770
+ """
771
+ Downloads a YouTube video and returns the maximum number of unique bird species
772
+ visible in any frame, along with the timestamp.
773
+
774
+ Parameters:
775
+ url (str): YouTube video URL
776
+
777
+ Returns:
778
+ dict: {
779
+ "max_species_count": int,
780
+ "timestamp": str,
781
+ "species_list": List[str],
782
+ }
783
+ """
784
+ # 1. Download YouTube video
785
+ yt = YouTube(url)
786
+ stream = yt.streams.filter(file_extension='mp4').get_highest_resolution()
787
+ temp_video_path = os.path.join(tempfile.gettempdir(), "video.mp4")
788
+ stream.download(filename=temp_video_path)
789
+
790
+ # 2. Load object detection model for bird species
791
+ # Load a fine-tuned YOLOv5 model or similar pretrained on bird species
792
+ model = torch.hub.load('ultralytics/yolov5', 'custom', path='best_birds.pt') # path to your trained model
793
+
794
+ # 3. Process video frames
795
+ cap = cv2.VideoCapture(temp_video_path)
796
+ fps = cap.get(cv2.CAP_PROP_FPS)
797
+ frame_interval = int(fps * 1) # 1 frame per second
798
+
799
+ max_species_count = 0
800
+ max_species_frame_time = 0
801
+ species_at_max = []
802
+
803
+ frame_idx = 0
804
+ while cap.isOpened():
805
+ ret, frame = cap.read()
806
+ if not ret:
807
+ break
808
+ if frame_idx % frame_interval == 0:
809
+ # Run detection
810
+ results = model(frame)
811
+ detected_species = set()
812
+ for *box, conf, cls in results.xyxy[0]:
813
+ species_name = model.names[int(cls)]
814
+ detected_species.add(species_name)
815
+
816
+ if len(detected_species) > max_species_count:
817
+ max_species_count = len(detected_species)
818
+ max_species_frame_time = int(cap.get(cv2.CAP_PROP_POS_MSEC)) // 1000
819
+ species_at_max = list(detected_species)
820
+
821
+ frame_idx += 1
822
+
823
+ cap.release()
824
+ os.remove(temp_video_path)
825
+
826
+ return {
827
+ "max_species_count": max_species_count,
828
+ "timestamp": f"{max_species_frame_time}s",
829
+ "species_list": species_at_max
830
+ }