Spaces:
Sleeping
Sleeping
Alexandre Gazola
commited on
Commit
·
f66d8b7
1
Parent(s):
8ee60f3
codigo agente
Browse files- audio_to_text_tool.py +61 -0
- botanical_classification_tool.py +190 -0
- constants.py +30 -0
- convert_to_fen_tool copy.py +40 -0
- count_max_distinct_bird_species_tool.py +82 -0
- download_task_file.py +46 -0
- excel_parser_tool.py +42 -0
- image_to_text_tool.py +55 -0
- internet_search_tool.py +50 -0
- python_interpreter_tool.py +55 -0
- sample_youtube_video.py +96 -0
- supervisor.py +77 -0
- video_to_text_tool.py +107 -0
- wikipedia_tool.py +219 -0
audio_to_text_tool.py
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import whisper
|
2 |
+
from langchain_core.tools import tool
|
3 |
+
|
4 |
+
#@tool
|
5 |
+
import whisper
|
6 |
+
import os
|
7 |
+
|
8 |
+
import os
|
9 |
+
import whisper
|
10 |
+
import subprocess
|
11 |
+
import tempfile
|
12 |
+
|
13 |
+
import os
|
14 |
+
import whisper
|
15 |
+
import subprocess
|
16 |
+
import tempfile
|
17 |
+
|
18 |
+
def audio_to_text(file_path: str) -> str:
|
19 |
+
"""
|
20 |
+
Converts an MP3 file to WAV and transcribes it using Whisper.
|
21 |
+
|
22 |
+
Args:
|
23 |
+
file_path (str): Path to the MP3 file.
|
24 |
+
|
25 |
+
Returns:
|
26 |
+
str: Transcribed text.
|
27 |
+
"""
|
28 |
+
if not os.path.isfile(file_path):
|
29 |
+
raise FileNotFoundError(f"File not found: {file_path}")
|
30 |
+
|
31 |
+
# Convert MP3 to temporary WAV file
|
32 |
+
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_wav:
|
33 |
+
tmp_wav_path = tmp_wav.name
|
34 |
+
|
35 |
+
try:
|
36 |
+
# Convert to WAV using ffmpeg
|
37 |
+
subprocess.run(
|
38 |
+
["ffmpeg", "-y", "-i", file_path, tmp_wav_path],
|
39 |
+
stdout=subprocess.DEVNULL,
|
40 |
+
stderr=subprocess.DEVNULL,
|
41 |
+
check=True
|
42 |
+
)
|
43 |
+
|
44 |
+
model = whisper.load_model("base")
|
45 |
+
result = model.transcribe(tmp_wav_path)
|
46 |
+
|
47 |
+
if result is None or "text" not in result:
|
48 |
+
raise ValueError("Transcription failed or result is invalid.")
|
49 |
+
|
50 |
+
return result["text"]
|
51 |
+
|
52 |
+
finally:
|
53 |
+
# Clean up temporary WAV file
|
54 |
+
if os.path.exists(tmp_wav_path):
|
55 |
+
os.remove(tmp_wav_path)
|
56 |
+
|
57 |
+
if __name__ == "__main__":
|
58 |
+
try:
|
59 |
+
print(audio_to_text("C:\\tmp\\ibm\\audio.mp3"))
|
60 |
+
except Exception as e:
|
61 |
+
print(f"Error: {e}")
|
botanical_classification_tool.py
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain_core.tools import tool
|
2 |
+
|
3 |
+
@tool
|
4 |
+
def get_botanical_classification(item_name):
|
5 |
+
"""
|
6 |
+
Provides the botanical classification (fruit, vegetable, or other)
|
7 |
+
for a given food item, adhering to botanical definitions.
|
8 |
+
|
9 |
+
Args:
|
10 |
+
item_name (str): The name of the food item (e.g., "bell pepper", "sweet potato").
|
11 |
+
|
12 |
+
Returns:
|
13 |
+
dict: A dictionary containing:
|
14 |
+
- 'item': The normalized item name.
|
15 |
+
- 'botanical_category': 'fruit', 'vegetable', 'other', or 'unclassified'.
|
16 |
+
- 'botanical_part': The botanical part of the plant (e.g., 'matured ovary', 'root', 'leaf'),
|
17 |
+
or 'N/A' if not applicable/unknown.
|
18 |
+
- 'notes': Any additional botanical notes or clarifications.
|
19 |
+
"""
|
20 |
+
|
21 |
+
# --- Curated Botanical Database ---
|
22 |
+
# This dictionary holds the botanical classifications.
|
23 |
+
# It's crucial this data is accurate according to botanical science.
|
24 |
+
# You will need to expand this as needed for your full grocery list.
|
25 |
+
botanical_data = {
|
26 |
+
"sweet potatoes": {
|
27 |
+
"botanical_category": "vegetable",
|
28 |
+
"botanical_part": "root/tuber",
|
29 |
+
"notes": "Edible root of the plant."
|
30 |
+
},
|
31 |
+
"fresh basil": {
|
32 |
+
"botanical_category": "vegetable",
|
33 |
+
"botanical_part": "leaf",
|
34 |
+
"notes": "Edible leaves of the herb."
|
35 |
+
},
|
36 |
+
"plums": {
|
37 |
+
"botanical_category": "fruit",
|
38 |
+
"botanical_part": "matured ovary",
|
39 |
+
"notes": "Simple fleshy fruit (drupe)."
|
40 |
+
},
|
41 |
+
"green beans": {
|
42 |
+
"botanical_category": "fruit",
|
43 |
+
"botanical_part": "matured ovary (legume)",
|
44 |
+
"notes": "Botanically a fruit (legume) containing seeds."
|
45 |
+
},
|
46 |
+
"rice": {
|
47 |
+
"botanical_category": "fruit",
|
48 |
+
"botanical_part": "matured ovary (caryopsis)",
|
49 |
+
"notes": "A grain, which is botanically a dry fruit (caryopsis)."
|
50 |
+
},
|
51 |
+
"corn": {
|
52 |
+
"botanical_category": "fruit",
|
53 |
+
"botanical_part": "matured ovary (caryopsis)",
|
54 |
+
"notes": "A grain, which is botanically a dry fruit (caryopsis)."
|
55 |
+
},
|
56 |
+
"bell pepper": {
|
57 |
+
"botanical_category": "fruit",
|
58 |
+
"botanical_part": "matured ovary",
|
59 |
+
"notes": "Developed from the flower's ovary and contains seeds."
|
60 |
+
},
|
61 |
+
"whole allspice": { # Allspice berries
|
62 |
+
"botanical_category": "fruit",
|
63 |
+
"botanical_part": "dried berry",
|
64 |
+
"notes": "Dried unripe berries of the Pimenta dioica plant."
|
65 |
+
},
|
66 |
+
"acorns": {
|
67 |
+
"botanical_category": "fruit",
|
68 |
+
"botanical_part": "nut (type of dry fruit)",
|
69 |
+
"notes": "A nut, which is botanically a type of dry fruit."
|
70 |
+
},
|
71 |
+
"broccoli": {
|
72 |
+
"botanical_category": "vegetable",
|
73 |
+
"botanical_part": "flower/stem",
|
74 |
+
"notes": "Edible flower heads and stalks."
|
75 |
+
},
|
76 |
+
"celery": {
|
77 |
+
"botanical_category": "vegetable",
|
78 |
+
"botanical_part": "stem/petiole",
|
79 |
+
"notes": "Edible leaf stalks."
|
80 |
+
},
|
81 |
+
"zucchini": {
|
82 |
+
"botanical_category": "fruit",
|
83 |
+
"botanical_part": "matured ovary",
|
84 |
+
"notes": "A type of berry (pepo) from a flowering plant."
|
85 |
+
},
|
86 |
+
"lettuce": {
|
87 |
+
"botanical_category": "vegetable",
|
88 |
+
"botanical_part": "leaf",
|
89 |
+
"notes": "Edible leaves."
|
90 |
+
},
|
91 |
+
"peanuts": {
|
92 |
+
"botanical_category": "fruit",
|
93 |
+
"botanical_part": "legume (matured ovary)",
|
94 |
+
"notes": "Botanically a fruit (legume), despite growing underground."
|
95 |
+
},
|
96 |
+
# Non-plant items or items not strictly fruit/vegetable botanically
|
97 |
+
"milk": {
|
98 |
+
"botanical_category": "other",
|
99 |
+
"botanical_part": "N/A",
|
100 |
+
"notes": "Dairy product (animal)."
|
101 |
+
},
|
102 |
+
"eggs": {
|
103 |
+
"botanical_category": "other",
|
104 |
+
"botanical_part": "N/A",
|
105 |
+
"notes": "Animal product."
|
106 |
+
},
|
107 |
+
"flour": {
|
108 |
+
"botanical_category": "other",
|
109 |
+
"botanical_part": "N/A",
|
110 |
+
"notes": "Processed grain product (typically wheat, which is a fruit)."
|
111 |
+
},
|
112 |
+
"whole bean coffee": {
|
113 |
+
"botanical_category": "other", # The bean itself is a seed, not the entire fruit
|
114 |
+
"botanical_part": "seed",
|
115 |
+
"notes": "The coffee 'bean' is botanically the seed of the coffee cherry (a fruit)."
|
116 |
+
},
|
117 |
+
"oreos": {
|
118 |
+
"botanical_category": "other",
|
119 |
+
"botanical_part": "N/A",
|
120 |
+
"notes": "Processed food item."
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
# Normalize the input item name for lookup
|
125 |
+
normalized_item = item_name.strip().lower()
|
126 |
+
|
127 |
+
# Handle pluralization/singularization for common cases if not explicitly in data
|
128 |
+
# This is a simple approach; for more robustness, you'd need a proper NLP library.
|
129 |
+
if normalized_item.endswith("s") and normalized_item[:-1] in botanical_data:
|
130 |
+
normalized_item = normalized_item[:-1]
|
131 |
+
elif normalized_item + "s" in botanical_data:
|
132 |
+
# Check if the plural form exists if input is singular
|
133 |
+
if item_name.strip().lower() + "s" in botanical_data:
|
134 |
+
normalized_item = item_name.strip().lower() + "s"
|
135 |
+
|
136 |
+
# Retrieve classification
|
137 |
+
classification = botanical_data.get(normalized_item)
|
138 |
+
|
139 |
+
if classification:
|
140 |
+
return {
|
141 |
+
"item": item_name,
|
142 |
+
"botanical_category": classification["botanical_category"],
|
143 |
+
"botanical_part": classification["botanical_part"],
|
144 |
+
"notes": classification["notes"]
|
145 |
+
}
|
146 |
+
else:
|
147 |
+
# If the item is not found in the database
|
148 |
+
return {
|
149 |
+
"item": item_name,
|
150 |
+
"botanical_category": "unclassified",
|
151 |
+
"botanical_part": "N/A",
|
152 |
+
"notes": "Classification not found in the current database."
|
153 |
+
}
|
154 |
+
|
155 |
+
# --- Example Usage ---
|
156 |
+
if __name__ == "__main__":
|
157 |
+
grocery_list = [
|
158 |
+
"milk", "eggs", "flour", "whole bean coffee", "Oreos", "sweet potatoes",
|
159 |
+
"fresh basil", "plums", "green beans", "rice", "corn", "bell pepper",
|
160 |
+
"whole allspice", "acorns", "broccoli", "celery", "zucchini", "lettuce",
|
161 |
+
"peanuts"
|
162 |
+
]
|
163 |
+
|
164 |
+
botanical_fruits = []
|
165 |
+
botanical_vegetables = []
|
166 |
+
other_items = []
|
167 |
+
unclassified_items = []
|
168 |
+
|
169 |
+
print("--- Botanical Classifications ---")
|
170 |
+
for item in grocery_list:
|
171 |
+
classification = get_botanical_classification(item)
|
172 |
+
print(f"'{classification['item']}' -> Category: {classification['botanical_category']}, Part: {classification['botanical_part']} ({classification['notes']})")
|
173 |
+
|
174 |
+
if classification['botanical_category'] == 'fruit':
|
175 |
+
botanical_fruits.append(classification['item'])
|
176 |
+
elif classification['botanical_category'] == 'vegetable':
|
177 |
+
botanical_vegetables.append(classification['item'])
|
178 |
+
elif classification['botanical_category'] == 'other':
|
179 |
+
other_items.append(classification['item'])
|
180 |
+
else: # unclassified
|
181 |
+
unclassified_items.append(classification['item'])
|
182 |
+
|
183 |
+
print("\n--- Summary ---")
|
184 |
+
print(f"Botanical Fruits: {', '.join(sorted(botanical_fruits))}")
|
185 |
+
print(f"Botanical Vegetables: {', '.join(sorted(botanical_vegetables))}")
|
186 |
+
print(f"Other Groceries: {', '.join(sorted(other_items))}")
|
187 |
+
if unclassified_items:
|
188 |
+
print(f"Unclassified Items: {', '.join(sorted(unclassified_items))}")
|
189 |
+
|
190 |
+
print(get_botanical_classification('fresh basil'))
|
constants.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# MODEL = 'gemini-2.0-flash'
|
2 |
+
MODEL = 'gemini-2.0-flash-exp'
|
3 |
+
# MODEL = 'gemini-2.5-pro-exp-03-25'
|
4 |
+
# 'gemini-2.5-pro-exp-03-25'
|
5 |
+
# gemini-2.0-flash
|
6 |
+
# gemini-2.5-pro-exp-03-25
|
7 |
+
|
8 |
+
API_KEY = 'AIzaSyDfVJVwfEhMpZCFNg91TWwXBvs0BZsMpPo'
|
9 |
+
|
10 |
+
OPENAI_KEY = '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'
|
11 |
+
|
12 |
+
PROMPT_LIMITADOR_LLM = """
|
13 |
+
You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings. If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise. If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise. If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.
|
14 |
+
|
15 |
+
However, if I give you tools that access the internet, you may freely use them. In particular, you have a tool that allows you to search the internet. Use it when necessary.
|
16 |
+
|
17 |
+
Your primary goal is to assist me using only the tools and data I make available. If a task requires information or capabilities beyond what I have provided, you must clearly state that you cannot fulfill the request due to these limitations.
|
18 |
+
|
19 |
+
Do not attempt to:
|
20 |
+
- Access external websites or databases without the tools that I provide.
|
21 |
+
- Use any internal knowledge base beyond what I provide.
|
22 |
+
- Categorize food items based on your own knowledge. Use the provided tools. Run the provided tools on every item of the grocery list!
|
23 |
+
- Make assumptions or inferences based on information not explicitly given.
|
24 |
+
- Utilize any built-in tools or functions that I have not specifically presented.
|
25 |
+
|
26 |
+
Your responses should be concise and directly address the task at hand, using only the provided resources. If a question cannot be answered or a task cannot be completed with the given constraints, your response should be a polite refusal stating the limitation.
|
27 |
+
|
28 |
+
Understood? Acknowledge that you will operate strictly within these constraints.
|
29 |
+
|
30 |
+
"""
|
convert_to_fen_tool copy.py
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import constants
|
4 |
+
from langchain_core.prompts import ChatPromptTemplate
|
5 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
6 |
+
from langgraph.graph import StateGraph, END
|
7 |
+
from typing import TypedDict, List, Dict
|
8 |
+
import google.generativeai as genai
|
9 |
+
|
10 |
+
def image_to_fen(image_bytes):
|
11 |
+
|
12 |
+
genai.configure(api_key=constants.API_KEY)
|
13 |
+
|
14 |
+
model = genai.GenerativeModel(constants.MODEL)
|
15 |
+
|
16 |
+
response = model.generate_content([
|
17 |
+
{"mime_type": "image/jpeg", "data": image_bytes},
|
18 |
+
"Describe the chessboard in this image and provide the FEN notation."
|
19 |
+
])
|
20 |
+
|
21 |
+
print(response.text)
|
22 |
+
|
23 |
+
return ''
|
24 |
+
|
25 |
+
if __name__ == '__main__':
|
26 |
+
# Example usage:
|
27 |
+
# 1. Load an image from a file (replace with your image path)
|
28 |
+
image_path = r"C:\Users\agazo\Downloads\cca530fc-4052-43b2-b130-b30968d8aa44_file.png" # Replace with a valid image path
|
29 |
+
try:
|
30 |
+
with open(image_path, "rb") as image_file:
|
31 |
+
image_bytes = image_file.read()
|
32 |
+
except FileNotFoundError:
|
33 |
+
print(f"Error: File not found at {image_path}. Please make sure the path is correct and the file exists.")
|
34 |
+
exit()
|
35 |
+
|
36 |
+
# 2. Call the function
|
37 |
+
fen = image_to_fen(image_bytes)
|
38 |
+
print(f"FEN: {fen}")
|
39 |
+
|
40 |
+
#resultado esperado do FEN; 1K6/1PP5/P2RBBqP/4n3/Q7/p2b4/1pp3pp/1k2r3 w - - 0 1
|
count_max_distinct_bird_species_tool.py
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from sample_youtube_video import sample_youtube_video
|
2 |
+
from ultralytics import YOLO
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
from utils import decode_base64_to_frame
|
5 |
+
|
6 |
+
@tool
|
7 |
+
def count_max_distinct_bird_species_in_video(youtube_url: str) -> int:
|
8 |
+
"""
|
9 |
+
Count the maximum number of distinct bird species in a YouTube video.
|
10 |
+
|
11 |
+
Args:
|
12 |
+
- youtube_url: str: the URL of the YouTube video
|
13 |
+
|
14 |
+
Returns:
|
15 |
+
- int: The maximum number of distinct bird species detected in the YouTube video.
|
16 |
+
"""
|
17 |
+
|
18 |
+
frames = sample_youtube_video(youtube_url, 5)
|
19 |
+
return count_max_distinct_bird_species(frames)
|
20 |
+
|
21 |
+
def count_max_distinct_bird_species(framesStr: list[str]) -> int:
|
22 |
+
"""
|
23 |
+
Count the maximum number of distinct bird species in a single frame considering a list of frames.
|
24 |
+
|
25 |
+
Args:
|
26 |
+
- frames (List[cv2.Mat]): A list of frames (images) to analyze.
|
27 |
+
|
28 |
+
Returns:
|
29 |
+
- int: The maximum number of distinct bird species detected in any single frame.
|
30 |
+
"""
|
31 |
+
|
32 |
+
# List of bird class indices from COCO dataset (class IDs for birds)
|
33 |
+
bird_class_ids = [
|
34 |
+
14, 15, 16, 17, 18, 19, 20, 21 # Example bird class IDs in COCO dataset
|
35 |
+
]
|
36 |
+
|
37 |
+
# Load YOLOv8 model for object detection (pre-trained or custom-trained for animals)
|
38 |
+
model = YOLO("yolov8n.pt") # Use a pre-trained YOLOv8 model
|
39 |
+
|
40 |
+
max_bird_species_count = 0 # To track the maximum count of distinct bird species
|
41 |
+
|
42 |
+
frames = [decode_base64_to_frame(b64) for b64 in framesStr]
|
43 |
+
|
44 |
+
# Iterate through all frames in the list
|
45 |
+
for frame in frames:
|
46 |
+
# Perform inference on the current frame
|
47 |
+
results = model(frame)
|
48 |
+
|
49 |
+
bird_species_detected = set() # To track distinct bird species in this frame
|
50 |
+
|
51 |
+
# Parse the detected objects
|
52 |
+
for result in results:
|
53 |
+
# Convert the class indices from tensor to integer
|
54 |
+
detected_classes = result.boxes.cls.int() # Convert tensor to int
|
55 |
+
|
56 |
+
# Iterate over detected classes and filter only bird species
|
57 |
+
for detected_class in detected_classes:
|
58 |
+
# If the class is a bird (based on COCO bird class IDs)
|
59 |
+
if detected_class.item() in bird_class_ids:
|
60 |
+
species_name = result.names[detected_class.item()] # Get the species name
|
61 |
+
bird_species_detected.add(species_name)
|
62 |
+
|
63 |
+
# Update the maximum number of distinct bird species detected in any frame
|
64 |
+
max_bird_species_count = max(max_bird_species_count, len(bird_species_detected))
|
65 |
+
|
66 |
+
# Return the maximum number of distinct bird species detected in any frame
|
67 |
+
return max_bird_species_count
|
68 |
+
|
69 |
+
|
70 |
+
if __name__ == "__main__":
|
71 |
+
sampled_frames = sample_youtube_video.invoke({
|
72 |
+
"youtube_url": "https://www.youtube.com/watch?v=L1vXCYZAYYM" ,
|
73 |
+
"sample_rate": 5
|
74 |
+
}
|
75 |
+
)
|
76 |
+
|
77 |
+
distinct_species_count = count.invoke({
|
78 |
+
"framesStr": sampled_frames
|
79 |
+
}
|
80 |
+
)
|
81 |
+
|
82 |
+
print(f"Distinct species detected: {distinct_species_count}")
|
download_task_file.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import requests
|
3 |
+
|
4 |
+
def download_file(task_id: str):
|
5 |
+
# Construct the URL
|
6 |
+
url = f"https://agents-course-unit4-scoring.hf.space/files/{task_id}"
|
7 |
+
|
8 |
+
# Send the request to download the file
|
9 |
+
response = requests.get(url)
|
10 |
+
|
11 |
+
if response.status_code == 200:
|
12 |
+
# Get the content type from the response headers to determine the file extension
|
13 |
+
content_type = response.headers.get('Content-Type', '')
|
14 |
+
file_extension = ''
|
15 |
+
|
16 |
+
# Map content types to file extensions
|
17 |
+
if 'pdf' in content_type:
|
18 |
+
file_extension = '.pdf'
|
19 |
+
elif 'jpg' in content_type or 'jpeg' in content_type:
|
20 |
+
file_extension = '.jpg'
|
21 |
+
elif 'png' in content_type:
|
22 |
+
file_extension = '.png'
|
23 |
+
elif 'txt' in content_type:
|
24 |
+
file_extension = '.txt'
|
25 |
+
elif 'zip' in content_type:
|
26 |
+
file_extension = '.zip'
|
27 |
+
elif 'mp3' in content_type:
|
28 |
+
file_extension = '.mp3'
|
29 |
+
# Add more file types as necessary
|
30 |
+
|
31 |
+
# If the extension can't be determined, default to .bin
|
32 |
+
if not file_extension:
|
33 |
+
file_extension = '.bin'
|
34 |
+
|
35 |
+
# Set the path to the Downloads folder (adjust 'YourUsername' to your actual username)
|
36 |
+
save_path = os.path.join(os.path.expanduser('~'), 'Downloads', f"{task_id}_file{file_extension}")
|
37 |
+
|
38 |
+
# Save the file with the appropriate extension
|
39 |
+
with open(save_path, 'wb') as f:
|
40 |
+
f.write(response.content)
|
41 |
+
print(f"File successfully downloaded and saved as {save_path}")
|
42 |
+
else:
|
43 |
+
print(f"Failed to download the file. Status code: {response.status_code}")
|
44 |
+
|
45 |
+
task_id = "7bd855d8-463d-4ed5-93ca-5fe35145f733"
|
46 |
+
download_file(task_id)
|
excel_parser_tool.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from duckduckgo_search import DDGS
|
2 |
+
from utils import clean_text
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
import io
|
5 |
+
import pandas as pd
|
6 |
+
import base64
|
7 |
+
from utils import get_base64
|
8 |
+
|
9 |
+
|
10 |
+
@tool
|
11 |
+
def parse_excel(base64_str: str) -> str:
|
12 |
+
"""Parses a base64-encoded Excel (.xlsx) file and returns a markdown summary."""
|
13 |
+
try:
|
14 |
+
file_bytes = base64.b64decode(base64_str)
|
15 |
+
excel_file = pd.ExcelFile(io.BytesIO(file_bytes))
|
16 |
+
|
17 |
+
output = []
|
18 |
+
for sheet in excel_file.sheet_names:
|
19 |
+
df = excel_file.parse(sheet)
|
20 |
+
output.append(f"### Sheet: {sheet}\n")
|
21 |
+
output.append(df.head(20).to_markdown(index=False))
|
22 |
+
output.append("\n")
|
23 |
+
|
24 |
+
return "\n".join(output)
|
25 |
+
except Exception as e:
|
26 |
+
return f"Error parsing Excel file: {e}"
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
if __name__ == "__main__":
|
31 |
+
import sys
|
32 |
+
|
33 |
+
filepath = 'C:\\Users\\agazo\\Downloads\\7bd855d8-463d-4ed5-93ca-5fe35145f733_file.xlsx'
|
34 |
+
|
35 |
+
try:
|
36 |
+
result = parse_excel(get_base64(filepath))
|
37 |
+
print(result)
|
38 |
+
|
39 |
+
except FileNotFoundError:
|
40 |
+
print(f"File not found: {filepath}")
|
41 |
+
except Exception as e:
|
42 |
+
print(f"Error: {e}")
|
image_to_text_tool.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import constants
|
2 |
+
import google.generativeai as genai
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
from PIL import Image
|
5 |
+
import io
|
6 |
+
|
7 |
+
@tool
|
8 |
+
def image_to_text(image_bytes, instructions):
|
9 |
+
"""
|
10 |
+
Generates a text describing an image.
|
11 |
+
|
12 |
+
Args:
|
13 |
+
image_bytes (bytes): the bytes of the image to de described.
|
14 |
+
instructions (str): instructions to describe the image.
|
15 |
+
|
16 |
+
Returns:
|
17 |
+
str: A string describing the image according to the instructions given.
|
18 |
+
"""
|
19 |
+
|
20 |
+
genai.configure(api_key=constants.API_KEY)
|
21 |
+
model = genai.GenerativeModel(constants.MODEL)
|
22 |
+
|
23 |
+
response = model.generate_content(
|
24 |
+
[
|
25 |
+
{
|
26 |
+
"mime_type": "image/jpeg",
|
27 |
+
"data": image_bytes
|
28 |
+
},
|
29 |
+
instructions
|
30 |
+
]
|
31 |
+
)
|
32 |
+
return response.text
|
33 |
+
|
34 |
+
if __name__ == '__main__':
|
35 |
+
# Example usage:
|
36 |
+
# 1. Load an image from a file (replace with your image path)
|
37 |
+
image_path = r"C:\Users\agazo\Downloads\cca530fc-4052-43b2-b130-b30968d8aa44_file.png" # Replace with a valid image path
|
38 |
+
try:
|
39 |
+
with open(image_path, "rb") as image_file:
|
40 |
+
image_bytes = image_file.read()
|
41 |
+
except FileNotFoundError:
|
42 |
+
print(f"Error: File not found at {image_path}. Please make sure the path is correct and the file exists.")
|
43 |
+
exit()
|
44 |
+
|
45 |
+
# 2. Call the function
|
46 |
+
text = image_to_text.invoke(
|
47 |
+
{
|
48 |
+
"image_bytes": image_bytes,
|
49 |
+
"instructions": 'Describe the chessboard in this image and provide the FEN notation.'
|
50 |
+
}
|
51 |
+
)
|
52 |
+
print(f"FEN: {text}")
|
53 |
+
|
54 |
+
#resultado esperado do FEN; 1K6/1PP5/P2RBBqP/4n3/Q7/p2b4/1pp3pp/1k2r3 w - - 0 1
|
55 |
+
# 3r2k1/pp4pp/4b2p/Q7/3n4/PqBBR2P/PP4P1/K7 w - - 0 1
|
internet_search_tool.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from duckduckgo_search import DDGS
|
2 |
+
from utils import clean_text
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
|
5 |
+
@tool
|
6 |
+
def internet_search(query: str, max_results: int = 10) -> list[dict]:
|
7 |
+
"""
|
8 |
+
Search the Internet for the given query and return a list of results.
|
9 |
+
|
10 |
+
Args:
|
11 |
+
query (str): The search query string.
|
12 |
+
max_results (int, optional): Maximum number of search results to return. Default is 10.
|
13 |
+
|
14 |
+
Returns:
|
15 |
+
list[dict]: A list of dictionaries containing search results. Each dictionary typically includes:
|
16 |
+
- 'title': The title of the result.
|
17 |
+
- 'href': The URL of the result.
|
18 |
+
- 'body': A short snippet or description.
|
19 |
+
|
20 |
+
Raises:
|
21 |
+
ValueError: If the query is empty or only whitespace.
|
22 |
+
"""
|
23 |
+
if not query.strip():
|
24 |
+
raise ValueError("Query must not be empty.")
|
25 |
+
|
26 |
+
results = []
|
27 |
+
with DDGS() as ddgs:
|
28 |
+
for r in ddgs.text(query):
|
29 |
+
results.append(r)
|
30 |
+
if len(results) >= max_results:
|
31 |
+
break
|
32 |
+
return results
|
33 |
+
|
34 |
+
if __name__ == "__main__":
|
35 |
+
query = 'Alexandre Gazola'
|
36 |
+
try:
|
37 |
+
results = internet_search.invoke(
|
38 |
+
{
|
39 |
+
"query": query,
|
40 |
+
"max_results": 5
|
41 |
+
}
|
42 |
+
)
|
43 |
+
|
44 |
+
for i, result in enumerate(results, 1):
|
45 |
+
print(f"\nResult {i}:")
|
46 |
+
print(f"Title: {clean_text(result.get('title'))}")
|
47 |
+
print(f"URL: {clean_text(result.get('href'))}")
|
48 |
+
print(f"Snippet: {clean_text(result.get('body'))}")
|
49 |
+
except ValueError as e:
|
50 |
+
print(f"Error: {e}")
|
python_interpreter_tool.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import constants
|
2 |
+
import google.generativeai as genai
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
from PIL import Image
|
5 |
+
import io
|
6 |
+
|
7 |
+
@tool
|
8 |
+
def image_to_text(image_bytes, instructions):
|
9 |
+
"""
|
10 |
+
Generates a text describing an image.
|
11 |
+
|
12 |
+
Args:
|
13 |
+
image_bytes (bytes): the bytes of the image to de described.
|
14 |
+
instructions (str): instructions to describe the image.
|
15 |
+
|
16 |
+
Returns:
|
17 |
+
str: A string describing the image according to the instructions given.
|
18 |
+
"""
|
19 |
+
|
20 |
+
genai.configure(api_key=constants.API_KEY)
|
21 |
+
model = genai.GenerativeModel(constants.MODEL)
|
22 |
+
|
23 |
+
response = model.generate_content(
|
24 |
+
[
|
25 |
+
{
|
26 |
+
"mime_type": "image/jpeg",
|
27 |
+
"data": image_bytes
|
28 |
+
},
|
29 |
+
instructions
|
30 |
+
]
|
31 |
+
)
|
32 |
+
return response.text
|
33 |
+
|
34 |
+
if __name__ == '__main__':
|
35 |
+
# Example usage:
|
36 |
+
# 1. Load an image from a file (replace with your image path)
|
37 |
+
image_path = r"C:\Users\agazo\Downloads\cca530fc-4052-43b2-b130-b30968d8aa44_file.png" # Replace with a valid image path
|
38 |
+
try:
|
39 |
+
with open(image_path, "rb") as image_file:
|
40 |
+
image_bytes = image_file.read()
|
41 |
+
except FileNotFoundError:
|
42 |
+
print(f"Error: File not found at {image_path}. Please make sure the path is correct and the file exists.")
|
43 |
+
exit()
|
44 |
+
|
45 |
+
# 2. Call the function
|
46 |
+
text = image_to_text.invoke(
|
47 |
+
{
|
48 |
+
"image_bytes": image_bytes,
|
49 |
+
"instructions": 'Describe the chessboard in this image and provide the FEN notation.'
|
50 |
+
}
|
51 |
+
)
|
52 |
+
print(f"FEN: {text}")
|
53 |
+
|
54 |
+
#resultado esperado do FEN; 1K6/1PP5/P2RBBqP/4n3/Q7/p2b4/1pp3pp/1k2r3 w - - 0 1
|
55 |
+
# 3r2k1/pp4pp/4b2p/Q7/3n4/PqBBR2P/PP4P1/K7 w - - 0 1
|
sample_youtube_video.py
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import yt_dlp
|
3 |
+
import os
|
4 |
+
from typing import List
|
5 |
+
from utils import encode_frame_to_base64
|
6 |
+
|
7 |
+
# Nota: Precisa ter a biblioteca ffmpeg instalada na maquina!
|
8 |
+
|
9 |
+
|
10 |
+
def sample_youtube_video(youtube_url: str, sample_rate: int) -> List[str]:
|
11 |
+
"""
|
12 |
+
Downloads a YouTube video and samples frames from it at a specified interval.
|
13 |
+
|
14 |
+
Args:
|
15 |
+
youtube_url (str): The URL of the YouTube video.
|
16 |
+
sample_rate (int): The interval (in seconds) at which to sample frames.
|
17 |
+
|
18 |
+
Returns:
|
19 |
+
List[cv2.Mat]: A list of sampled frames as cv2.Mat objects. Returns an empty list on error.
|
20 |
+
"""
|
21 |
+
|
22 |
+
frames: List[cv2.Mat] = []
|
23 |
+
|
24 |
+
# Construct the yt_dlp options
|
25 |
+
ydl_opts = {
|
26 |
+
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4', # Get the best quality video and audio in mp4 format
|
27 |
+
'outtmpl': '%(title)s.%(ext)s', # Save with the video title
|
28 |
+
'quiet': True, # Suppress console output
|
29 |
+
}
|
30 |
+
|
31 |
+
# Download the video
|
32 |
+
try:
|
33 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
34 |
+
info_dict = ydl.extract_info(youtube_url, download=True)
|
35 |
+
video_file = ydl.prepare_filename(info_dict) # Get the downloaded filename
|
36 |
+
except Exception as e:
|
37 |
+
print(f"Error downloading video: {e}")
|
38 |
+
return []
|
39 |
+
|
40 |
+
# Open the video file
|
41 |
+
try:
|
42 |
+
cap = cv2.VideoCapture(video_file)
|
43 |
+
except Exception as e:
|
44 |
+
print(f"Error opening video file: {e}")
|
45 |
+
return []
|
46 |
+
|
47 |
+
# Get the video's frame rate
|
48 |
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
49 |
+
if fps <= 0:
|
50 |
+
print("Error: Could not determine video frame rate. OpenCV may not be able to read this file.")
|
51 |
+
cap.release()
|
52 |
+
os.remove(video_file)
|
53 |
+
return []
|
54 |
+
|
55 |
+
# Calculate the frame interval
|
56 |
+
frame_interval = int(sample_rate * fps)
|
57 |
+
|
58 |
+
frame_count = 0
|
59 |
+
success = True
|
60 |
+
duration_seconds = float(info_dict.get('duration', 0))
|
61 |
+
|
62 |
+
while success:
|
63 |
+
success, frame = cap.read()
|
64 |
+
if not success:
|
65 |
+
break
|
66 |
+
|
67 |
+
if frame_count % frame_interval == 0:
|
68 |
+
# Get the current time stamp
|
69 |
+
current_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0 # in seconds
|
70 |
+
|
71 |
+
if current_time > duration_seconds and duration_seconds != 0:
|
72 |
+
break
|
73 |
+
frames.append(frame)
|
74 |
+
|
75 |
+
frame_count += 1
|
76 |
+
|
77 |
+
# Release the video capture object and remove the downloaded video file
|
78 |
+
cap.release()
|
79 |
+
try:
|
80 |
+
os.remove(video_file)
|
81 |
+
print(f"Deleted downloaded video file: {video_file}")
|
82 |
+
except Exception as e:
|
83 |
+
print(f"Error deleting video file: {e}")
|
84 |
+
|
85 |
+
print(f"Finished sampling. {len(frames)} frames sampled.")
|
86 |
+
|
87 |
+
return [encode_frame_to_base64(frame) for frame in frames]
|
88 |
+
|
89 |
+
|
90 |
+
if __name__ == "__main__":
|
91 |
+
sampled_frames = sample_youtube_video("https://www.youtube.com/watch?v=L1vXCYZAYYM", 5)
|
92 |
+
|
93 |
+
if sampled_frames:
|
94 |
+
print(f"Number of frames returned: {len(sampled_frames)}")
|
95 |
+
else:
|
96 |
+
print("No frames were returned.")
|
supervisor.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import constants
|
2 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
5 |
+
from langchain_core.runnables import Runnable
|
6 |
+
from langchain_openai import ChatOpenAI
|
7 |
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
8 |
+
from langchain_core.messages import SystemMessage
|
9 |
+
from wikipedia_tool import wikipedia_revision_by_year_keyword
|
10 |
+
from count_max_distinct_bird_species_tool import count_max_distinct_bird_species_in_video
|
11 |
+
from image_to_text_tool import image_to_text
|
12 |
+
from utils import get_bytes, get_text_file_contents, get_base64
|
13 |
+
from internet_search_tool import internet_search
|
14 |
+
from botanical_classification_tool import get_botanical_classification
|
15 |
+
from excel_parser_tool import parse_excel
|
16 |
+
|
17 |
+
llm = ChatGoogleGenerativeAI(
|
18 |
+
model=constants.MODEL,
|
19 |
+
api_key=constants.API_KEY,
|
20 |
+
temperature=0.7)
|
21 |
+
|
22 |
+
tools = [
|
23 |
+
wikipedia_revision_by_year_keyword,
|
24 |
+
count_max_distinct_bird_species_in_video,
|
25 |
+
image_to_text,
|
26 |
+
internet_search,
|
27 |
+
get_botanical_classification,
|
28 |
+
parse_excel
|
29 |
+
]
|
30 |
+
|
31 |
+
prompt = ChatPromptTemplate.from_messages([
|
32 |
+
SystemMessage(
|
33 |
+
content=(
|
34 |
+
constants.PROMPT_LIMITADOR_LLM
|
35 |
+
)
|
36 |
+
),
|
37 |
+
MessagesPlaceholder(variable_name="chat_history"),
|
38 |
+
("human", "{input}"),
|
39 |
+
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
40 |
+
])
|
41 |
+
|
42 |
+
agent = create_tool_calling_agent(llm, tools, prompt=prompt)
|
43 |
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
44 |
+
|
45 |
+
questoes = [
|
46 |
+
'How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)? You can use the latest 2022 version of english wikipedia.',
|
47 |
+
'In the video https://www.youtube.com/watch?v=L1vXCYZAYYM, what is the highest number of bird species to be on camera simultaneously?',
|
48 |
+
'.rewsna eht sa \"tfel\" drow eht fo etisoppo eht etirw ,ecnetnes siht dnatsrednu uoy fI', # trivial - o modelo responde
|
49 |
+
'Review the chess position provided in the image. It is blacks turn. Provide the correct next move for black which guarantees a win. Please provide your response in algebraic notation.',
|
50 |
+
'Who nominated the only Featured Article on English Wikipedia about a dinosaur that was promoted in November 2016?',
|
51 |
+
'Given this table defining * on the set S = {a, b, c, d, e}\n\n|*|a|b|c|d|e|\n|---|---|---|---|---|---|\n|a|a|b|c|b|d|\n|b|b|c|a|e|c|\n|c|c|a|b|b|a|\n|d|b|e|b|e|d|\n|e|d|b|a|d|c|\n\nprovide the subset of S involved in any possible counter-examples that prove * is not commutative. Provide your answer as a comma separated list of the elements in the set in alphabetical order.',
|
52 |
+
## questoes puladas
|
53 |
+
'What is the final numeric output from the attached Python code?', # trivial - o modelo responde
|
54 |
+
'How many at bats did the Yankee with the most walks in the 1977 regular season have that same season?',
|
55 |
+
"What is the surname of the equine veterinarian mentioned in 1.E Exercises from the chemistry materials licensed by Marisa Alviar-Agnew & Henry Agnew under the CK-12 license in LibreText's Introductory Chemistry materials as compiled 08/21/2023?",
|
56 |
+
"I'm making a grocery list for my mom, but she's a professor of botany and she's a real stickler when it comes to categorizing things. I need to add different foods to different categories on the grocery list, but if I make a mistake, she won't buy anything inserted in the wrong category. Here's the list I have so far:\n\nmilk, eggs, flour, whole bean coffee, Oreos, sweet potatoes, fresh basil, plums, green beans, rice, corn, bell pepper, whole allspice, acorns, broccoli, celery, zucchini, lettuce, peanuts\n\nI need to make headings for the fruits and vegetables. Could you please create a list of just the vegetables from my list? If you could do that, then I can figure out how to categorize the rest of the list into the appropriate categories. But remember that my mom is a real stickler, so make sure that no botanical fruits end up on the vegetable list, or she won't get them when she's at the store. Please alphabetize the list of vegetables, and place each item in a comma separated list.",
|
57 |
+
"Hi, I'm making a pie but I could use some help with my shopping list. I have everything I need for the crust, but I'm not sure about the filling. I got the recipe from my friend Aditi, but she left it as a voice memo and the speaker on my phone is buzzing so I can't quite make out what she's saying. Could you please listen to the recipe and list all of the ingredients that my friend described? I only want the ingredients for the filling, as I have everything I need to make my favorite pie crust. I've attached the recipe as Strawberry pie.mp3.\n\nIn your response, please only list the ingredients, not any measurements. So if the recipe calls for \"a pinch of salt\" or \"two cups of ripe strawberries\" the ingredients on the list would be \"salt\" and \"ripe strawberries\".\n\nPlease format your response as a comma separated list of ingredients. Also, please alphabetize the ingredients.",
|
58 |
+
"Who did the actor who played Ray in the Polish-language version of Everybody Loves Raymond play in Magda M.? Give only the first name.",
|
59 |
+
"What is the first name of the only Malko Competition recipient from the 20th Century (after 1977) whose nationality on record is a country that no longer exists?",
|
60 |
+
"What country had the least number of athletes at the 1928 Summer Olympics? If there's a tie for a number of athletes, return the first in alphabetical order. Give the IOC country code as your answer.",
|
61 |
+
"Where were the Vietnamese specimens described by Kuznetzov in Nedoshivina's 2010 paper eventually deposited? Just give me the city name without abbreviations. Look up the web.",
|
62 |
+
"The attached Excel file contains the sales of menu items for a local fast-food chain. What were the total sales that the chain made from food (not including drinks)? Express your answer in USD with two decimal places.",
|
63 |
+
]
|
64 |
+
|
65 |
+
# CUB
|
66 |
+
|
67 |
+
# resposta esperada: "Final answer": "broccoli, celery, fresh basil, lettuce, sweet potatoes"
|
68 |
+
|
69 |
+
#"Final answer": "89706.00"
|
70 |
+
|
71 |
+
response = agent_executor.invoke({
|
72 |
+
# "input": questoes[15],
|
73 |
+
"input": f"{questoes[15]} The relevant data is provided as a base64 encoded Excel file string. Here is the base64 string: {get_base64(r'C:\Users\agazo\Downloads\7bd855d8-463d-4ed5-93ca-5fe35145f733_file.xlsx')}",
|
74 |
+
"chat_history": []
|
75 |
+
})
|
76 |
+
|
77 |
+
print(response)
|
video_to_text_tool.py
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import os
|
3 |
+
import json
|
4 |
+
import constants
|
5 |
+
|
6 |
+
import requests
|
7 |
+
import os
|
8 |
+
import json
|
9 |
+
from pytube import YouTube
|
10 |
+
import subprocess
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
# Replace with your actual OpenAI API key
|
15 |
+
OPENAI_API_KEY = constants.OPENAI_KEY
|
16 |
+
|
17 |
+
# Replace with the URL of the YouTube video you want to transcribe
|
18 |
+
YOUTUBE_URL = "https://www.youtube.com/watch?v=1htKBjuUWec"
|
19 |
+
|
20 |
+
|
21 |
+
def download_youtube_audio(youtube_url, output_path="."):
|
22 |
+
"""Downloads the audio from a YouTube video.
|
23 |
+
|
24 |
+
Args:
|
25 |
+
youtube_url: The URL of the YouTube video.
|
26 |
+
output_path: The directory to save the audio file.
|
27 |
+
|
28 |
+
Returns:
|
29 |
+
str: The path to the downloaded audio file (in mp3 format), or None if an error occurs.
|
30 |
+
"""
|
31 |
+
try:
|
32 |
+
yt = YouTube(youtube_url)
|
33 |
+
audio_stream = yt.streams.filter(only_audio=True).first()
|
34 |
+
if audio_stream:
|
35 |
+
downloaded_file = audio_stream.download(output_path=output_path, filename="youtube_audio")
|
36 |
+
base, ext = os.path.splitext(downloaded_file)
|
37 |
+
mp3_file = os.path.join(output_path, f"{base}.mp3")
|
38 |
+
subprocess.call(['ffmpeg', '-i', downloaded_file, mp3_file])
|
39 |
+
os.remove(downloaded_file)
|
40 |
+
return mp3_file
|
41 |
+
else:
|
42 |
+
print("Error: No audio stream found for this video.")
|
43 |
+
return None
|
44 |
+
except Exception as e:
|
45 |
+
print(f"Error downloading YouTube audio: {e}")
|
46 |
+
return None
|
47 |
+
|
48 |
+
def transcribe_audio_openai(audio_file_path):
|
49 |
+
"""
|
50 |
+
Transcribes an audio file using the OpenAI Audio API.
|
51 |
+
|
52 |
+
Args:
|
53 |
+
audio_file_path: The path to the audio file.
|
54 |
+
|
55 |
+
Returns:
|
56 |
+
str: The transcribed text, or None if an error occurs.
|
57 |
+
"""
|
58 |
+
headers = {
|
59 |
+
"Authorization": f"Bearer {OPENAI_API_KEY}",
|
60 |
+
}
|
61 |
+
files = {
|
62 |
+
"file": open(audio_file_path, "rb"),
|
63 |
+
}
|
64 |
+
data = {
|
65 |
+
"model": "whisper-1",
|
66 |
+
}
|
67 |
+
|
68 |
+
try:
|
69 |
+
response = requests.post("https://api.openai.com/v1/audio/transcriptions", headers=headers, files=files, data=data)
|
70 |
+
response.raise_for_status() # Raise an exception for bad status codes
|
71 |
+
return response.json().get("text")
|
72 |
+
except requests.exceptions.RequestException as e:
|
73 |
+
print(f"Error during OpenAI API call: {e}")
|
74 |
+
if response is not None:
|
75 |
+
print(f"Response status code: {response.status_code}")
|
76 |
+
try:
|
77 |
+
print(f"Response body: {response.json()}")
|
78 |
+
except json.JSONDecodeError:
|
79 |
+
print(f"Response body (non-JSON): {response.content.decode()}")
|
80 |
+
return None
|
81 |
+
except Exception as e:
|
82 |
+
print(f"An unexpected error occurred: {e}")
|
83 |
+
return None
|
84 |
+
|
85 |
+
if __name__ == "__main__":
|
86 |
+
youtube_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ" # Replace with your YouTube video URL
|
87 |
+
|
88 |
+
# Download the audio from the YouTube video
|
89 |
+
audio_file_path = download_youtube_audio(youtube_url)
|
90 |
+
|
91 |
+
if audio_file_path:
|
92 |
+
print(f"Audio downloaded to: {audio_file_path}")
|
93 |
+
|
94 |
+
# Transcribe the downloaded audio using OpenAI
|
95 |
+
transcription = transcribe_audio_openai(audio_file_path)
|
96 |
+
|
97 |
+
# Clean up the downloaded audio file
|
98 |
+
os.remove(audio_file_path)
|
99 |
+
print(f"Deleted temporary audio file: {audio_file_path}")
|
100 |
+
|
101 |
+
if transcription:
|
102 |
+
print("\nYouTube Video Transcription (via OpenAI):")
|
103 |
+
print(transcription)
|
104 |
+
else:
|
105 |
+
print("Failed to transcribe the audio using OpenAI.")
|
106 |
+
else:
|
107 |
+
print("Could not download audio from the YouTube video.")
|
wikipedia_tool.py
ADDED
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import wikipediaapi
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
|
5 |
+
@tool
|
6 |
+
def wikipedia_revision_by_year_keyword(keyword: str, year: int) -> dict:
|
7 |
+
"""
|
8 |
+
Search for a Wikipedia page and get the latest revision from that year.
|
9 |
+
This tool allows you to search within the page content.
|
10 |
+
"""
|
11 |
+
search_url = (
|
12 |
+
f"https://en.wikipedia.org/w/api.php"
|
13 |
+
f"?action=query"
|
14 |
+
f"&list=search"
|
15 |
+
f"&format=json"
|
16 |
+
f"&srsearch={requests.utils.quote(keyword)}"
|
17 |
+
f"&srlimit=1"
|
18 |
+
)
|
19 |
+
search_response = requests.get(search_url, verify=False).json()
|
20 |
+
search_results = search_response.get("query", {}).get("search", [])
|
21 |
+
if not search_results:
|
22 |
+
return {"error": f"No Wikipedia page found for '{keyword}'."}
|
23 |
+
title = search_results[0]["title"]
|
24 |
+
|
25 |
+
timestamp = f"{year}-12-31T23:59:59Z"
|
26 |
+
rev_url = (
|
27 |
+
f"https://en.wikipedia.org/w/api.php"
|
28 |
+
f"?action=query"
|
29 |
+
f"&format=json"
|
30 |
+
f"&prop=revisions"
|
31 |
+
f"&titles={requests.utils.quote(title)}"
|
32 |
+
f"&rvlimit=1"
|
33 |
+
f"&rvprop=timestamp|user|comment|content"
|
34 |
+
f"&rvdir=older"
|
35 |
+
f"&rvstart={timestamp}"
|
36 |
+
)
|
37 |
+
rev_response = requests.get(rev_url, verify=False).json()
|
38 |
+
pages = rev_response.get("query", {}).get("pages", {})
|
39 |
+
page = next(iter(pages.values()), {})
|
40 |
+
if "revisions" not in page:
|
41 |
+
return {"error": f"No revision found for page '{title}' before {timestamp}."}
|
42 |
+
|
43 |
+
rev = page["revisions"][0]
|
44 |
+
return {
|
45 |
+
"title": title,
|
46 |
+
"timestamp": rev["timestamp"],
|
47 |
+
"user": rev["user"],
|
48 |
+
"comment": rev.get("comment", ""),
|
49 |
+
"content": rev.get("*", "[Content omitted]")
|
50 |
+
}
|
51 |
+
|
52 |
+
|
53 |
+
import requests
|
54 |
+
|
55 |
+
USER_AGENT = "MyGenericTool/1.0 ([email protected])" # Replace with your info
|
56 |
+
|
57 |
+
def get_all_featured_articles():
|
58 |
+
"""
|
59 |
+
Retrieves a list of titles of all Featured Articles on English Wikipedia.
|
60 |
+
"""
|
61 |
+
url = "https://en.wikipedia.org/w/api.php"
|
62 |
+
params = {
|
63 |
+
'action': 'query',
|
64 |
+
'format': 'json',
|
65 |
+
'list': 'categorymembers',
|
66 |
+
'cmtitle': 'Category:Featured articles',
|
67 |
+
'cmtype': 'page',
|
68 |
+
'cmlimit': 'max'
|
69 |
+
}
|
70 |
+
headers = {'User-Agent': USER_AGENT}
|
71 |
+
|
72 |
+
try:
|
73 |
+
response = requests.get(url, params=params, headers=headers, verify=False)
|
74 |
+
response.raise_for_status()
|
75 |
+
data = response.json()
|
76 |
+
featured_articles = [cm['title'] for cm in data.get('query', {}).get('categorymembers', [])]
|
77 |
+
return featured_articles
|
78 |
+
except requests.exceptions.RequestException as e:
|
79 |
+
print(f"Error fetching featured articles: {e}")
|
80 |
+
return []
|
81 |
+
|
82 |
+
def get_article_promotion_date(title):
|
83 |
+
"""
|
84 |
+
Retrieves the date (YYYY-MM) when an article was promoted to Featured Article status.
|
85 |
+
Looks for the date in the talk page history based on "Wikipedia:Featured article candidates" comments.
|
86 |
+
"""
|
87 |
+
talk_page_title = f"Talk:{title}"
|
88 |
+
url = "https://en.wikipedia.org/w/api.php"
|
89 |
+
params = {
|
90 |
+
'action': 'query',
|
91 |
+
'format': 'json',
|
92 |
+
'titles': talk_page_title,
|
93 |
+
'prop': 'revisions',
|
94 |
+
'rvprop': 'timestamp|user|comment',
|
95 |
+
'rvlimit': '50', # Adjust limit as needed
|
96 |
+
'rvdir': 'older'
|
97 |
+
}
|
98 |
+
headers = {'User-Agent': USER_AGENT}
|
99 |
+
|
100 |
+
try:
|
101 |
+
response = requests.get(url, params=params, headers=headers, verify=False)
|
102 |
+
response.raise_for_status()
|
103 |
+
data = response.json()
|
104 |
+
page_data = next(iter(data.get('query', {}).get('pages', {}).values()), {})
|
105 |
+
revisions = page_data.get('revisions', [])
|
106 |
+
for rev in revisions:
|
107 |
+
if "Wikipedia:Featured article candidates" in rev.get('comment', ''):
|
108 |
+
timestamp = rev.get('timestamp')
|
109 |
+
if timestamp and "promoted" in rev.get('comment', '').lower():
|
110 |
+
return timestamp[:7] # Return YYYY-MM
|
111 |
+
return None
|
112 |
+
except requests.exceptions.RequestException as e:
|
113 |
+
print(f"Error fetching talk page history for {title}: {e}")
|
114 |
+
return None
|
115 |
+
|
116 |
+
def get_nomination_user(title, promotion_month_year):
|
117 |
+
"""
|
118 |
+
Retrieves the user who nominated a Featured Article promoted in a specific month and year.
|
119 |
+
Looks for the nomination discussion on the talk page.
|
120 |
+
"""
|
121 |
+
talk_page_title = f"Talk:{title}"
|
122 |
+
url = "https://en.wikipedia.org/w/api.php"
|
123 |
+
params = {
|
124 |
+
'action': 'query',
|
125 |
+
'format': 'json',
|
126 |
+
'titles': talk_page_title,
|
127 |
+
'prop': 'revisions',
|
128 |
+
'rvprop': 'timestamp|user|comment',
|
129 |
+
'rvlimit': '500', # Adjust limit as needed
|
130 |
+
'rvdir': 'older'
|
131 |
+
}
|
132 |
+
headers = {'User-Agent': USER_AGENT}
|
133 |
+
|
134 |
+
try:
|
135 |
+
response = requests.get(url, params=params, headers=headers)
|
136 |
+
response.raise_for_status()
|
137 |
+
data = response.json()
|
138 |
+
page_data = next(iter(data.get('query', {}).get('pages', {}).values()), {})
|
139 |
+
revisions = page_data.get('revisions', [])
|
140 |
+
nomination_start_comment = None
|
141 |
+
for rev in reversed(revisions): # Look from newest to oldest
|
142 |
+
if f"Wikipedia:Featured article candidates/{title}" in rev.get('comment', ''):
|
143 |
+
nomination_start_comment = rev
|
144 |
+
break
|
145 |
+
|
146 |
+
if nomination_start_comment:
|
147 |
+
# Now, go back in history to find who initiated this section
|
148 |
+
params_history = {
|
149 |
+
'action': 'query',
|
150 |
+
'format': 'json',
|
151 |
+
'titles': talk_page_title,
|
152 |
+
'prop': 'revisions',
|
153 |
+
'rvprop': 'timestamp|user|comment',
|
154 |
+
'rvlimit': '500',
|
155 |
+
'rvdir': 'newer',
|
156 |
+
'rvstart': nomination_start_comment['timestamp']
|
157 |
+
}
|
158 |
+
response_history = requests.get(url, params=params_history, headers=headers)
|
159 |
+
response_history.raise_for_status()
|
160 |
+
data_history = response_history.json()
|
161 |
+
page_data_history = next(iter(data_history.get('query', {}).get('pages', {}).values()), {})
|
162 |
+
revisions_history = page_data_history.get('revisions', [])
|
163 |
+
if revisions_history:
|
164 |
+
return revisions_history[0].get('user') # The first edit in the section is likely the nominator
|
165 |
+
|
166 |
+
return None
|
167 |
+
except requests.exceptions.RequestException as e:
|
168 |
+
print(f"Error fetching talk page history for {title}: {e}")
|
169 |
+
return None
|
170 |
+
|
171 |
+
def find_nominator_of_fa_by_promotion_date(month_year):
|
172 |
+
"""
|
173 |
+
Finds the nominator of the (presumably single) Featured Article promoted in the given month and year.
|
174 |
+
|
175 |
+
Args:
|
176 |
+
month_year (str): The promotion month and year in 'YYYY-MM' format.
|
177 |
+
|
178 |
+
Returns:
|
179 |
+
tuple: A tuple containing the title of the Featured Article and the nominator's username,
|
180 |
+
or (None, None) if no single FA was found for that month/year.
|
181 |
+
"""
|
182 |
+
all_featured_articles = get_all_featured_articles()
|
183 |
+
promoted_in_month = []
|
184 |
+
for article in all_featured_articles:
|
185 |
+
promotion_date = get_article_promotion_date(article)
|
186 |
+
if promotion_date == month_year:
|
187 |
+
promoted_in_month.append(article)
|
188 |
+
|
189 |
+
if len(promoted_in_month) == 1:
|
190 |
+
target_article = promoted_in_month[0]
|
191 |
+
nominator = get_nomination_user(target_article, month_year)
|
192 |
+
return target_article, nominator
|
193 |
+
elif not promoted_in_month:
|
194 |
+
print(f"No Featured Article was found to be promoted in {month_year}.")
|
195 |
+
return None, None
|
196 |
+
else:
|
197 |
+
print(f"More than one Featured Article was promoted in {month_year}. Please be more specific.")
|
198 |
+
return None, None
|
199 |
+
|
200 |
+
if __name__ == "__main__":
|
201 |
+
import sys
|
202 |
+
import io
|
203 |
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
204 |
+
|
205 |
+
featured_articles = get_all_featured_articles()
|
206 |
+
if featured_articles:
|
207 |
+
print("All Featured Articles:")
|
208 |
+
for article in featured_articles:
|
209 |
+
print(article) # Printing Unicode strings should now work if stdout is UTF-8
|
210 |
+
|
211 |
+
target_month_year = "2016-11" # Example: November 2016
|
212 |
+
article_title, nominator_username = find_nominator_of_fa_by_promotion_date(target_month_year)
|
213 |
+
|
214 |
+
if article_title and nominator_username:
|
215 |
+
print(f"\nThe Featured Article '{article_title}' was promoted in {target_month_year} and was nominated by: {nominator_username}")
|
216 |
+
elif article_title:
|
217 |
+
print(f"\nThe Featured Article '{article_title}' was promoted in {target_month_year}, but the nominator could not be determined.")
|
218 |
+
elif article_title is None:
|
219 |
+
pass # Message already printed by find_nominator_of_fa_by_promotion_date
|