razvanfischer commited on
Commit
dbb37c1
·
1 Parent(s): ef1b18f
Files changed (3) hide show
  1. .gitignore +1 -0
  2. app.py +171 -36
  3. requirements.txt +205 -9
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ venv
app.py CHANGED
@@ -1,14 +1,16 @@
1
  import os
2
  import gradio as gr
3
- import requests
4
- import inspect
5
  import pandas as pd
6
  import asyncio
 
7
  from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec
8
  from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
9
  from llama_index.core.agent.workflow import AgentWorkflow
10
- from llama_index.core import SummaryIndex
11
  from llama_index.readers.web import SimpleWebPageReader
 
 
 
12
  from llama_index.core.agent.workflow import (
13
  AgentInput,
14
  AgentOutput,
@@ -16,53 +18,183 @@ from llama_index.core.agent.workflow import (
16
  ToolCallResult,
17
  AgentStream,
18
  )
19
-
 
 
20
 
21
  # (Keep Constants as is)
22
  # --- Constants ---
23
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
24
 
 
25
  # --- Basic Agent Definition ---
26
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
27
  class BasicAgent:
28
  def __init__(self):
29
  self.llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct")
 
 
 
 
30
  system_prompt = """
31
- You are a helpful assistant that answers questions. If you don't know the answer, you can search the web for information.
32
- If you are searching the web, keep the query very concise in order to get good results.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  """
34
- self.agent = AgentWorkflow.from_tools_or_functions([search_web], llm=self.llm,
 
 
 
35
  system_prompt=system_prompt)
36
  print("BasicAgent initialized.")
37
-
38
  async def __call__(self, question: str) -> str:
39
  handler = self.agent.run(user_msg=question)
40
- async for event in handler.stream_events():
41
- if isinstance(event, AgentStream):
42
- print(event.delta, end="", flush=True)
43
- elif isinstance(event, ToolCallResult):
44
- print(event.tool_name) # the tool name
45
- print(event.tool_kwargs) # the tool kwargs
46
- print(event.tool_output) # the tool output
47
  response = await handler
48
  return str(response)
49
 
50
- async def search_web(query: str) -> str:
51
- """Useful for using the web to answer questions. Keep the query very concise in order to get good results."""
52
- client = DuckDuckGoSearchToolSpec()
53
- search_res = client.duckduckgo_instant_search(query)
54
- return str(search_res)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- def run_and_submit_all( profile: gr.OAuthProfile | None):
57
  """
58
  Fetches all questions, runs the BasicAgent on them, submits all answers,
59
  and displays the results.
60
  """
61
  # --- Determine HF Space Runtime URL and Repo URL ---
62
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
63
 
64
  if profile:
65
- username= f"{profile.username}"
66
  print(f"User logged in: {username}")
67
  else:
68
  print("User not logged in.")
@@ -89,16 +221,16 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
89
  response.raise_for_status()
90
  questions_data = response.json()
91
  if not questions_data:
92
- print("Fetched questions list is empty.")
93
- return "Fetched questions list is empty or invalid format.", None
94
  print(f"Fetched {len(questions_data)} questions.")
95
  except requests.exceptions.RequestException as e:
96
  print(f"Error fetching questions: {e}")
97
  return f"Error fetching questions: {e}", None
98
  except requests.exceptions.JSONDecodeError as e:
99
- print(f"Error decoding JSON response from questions endpoint: {e}")
100
- print(f"Response text: {response.text[:500]}")
101
- return f"Error decoding server response for questions: {e}", None
102
  except Exception as e:
103
  print(f"An unexpected error occurred fetching questions: {e}")
104
  return f"An unexpected error occurred fetching questions: {e}", None
@@ -110,6 +242,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
110
  for item in questions_data:
111
  task_id = item.get("task_id")
112
  question_text = item.get("question")
 
113
  if not task_id or question_text is None:
114
  print(f"Skipping item with missing task_id or question: {item}")
115
  continue
@@ -118,14 +251,14 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
118
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
119
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
120
  except Exception as e:
121
- print(f"Error running agent on task {task_id}: {e}")
122
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
123
 
124
  if not answers_payload:
125
  print("Agent did not produce any answers to submit.")
126
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
127
 
128
- # 4. Prepare Submission
129
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
130
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
131
  print(status_update)
@@ -207,12 +340,14 @@ with gr.Blocks() as demo:
207
 
208
  if __name__ == "__main__":
209
  # agent = BasicAgent()
210
- # answ = asyncio.run(agent("Who is Michael Jackson?"))
 
 
211
 
212
- print("\n" + "-"*30 + " App Starting " + "-"*30)
213
  # Check for SPACE_HOST and SPACE_ID at startup for information
214
  space_host_startup = os.getenv("SPACE_HOST")
215
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
216
 
217
  if space_host_startup:
218
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -220,14 +355,14 @@ if __name__ == "__main__":
220
  else:
221
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
222
 
223
- if space_id_startup: # Print repo URLs if SPACE_ID is found
224
  print(f"✅ SPACE_ID found: {space_id_startup}")
225
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
226
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
227
  else:
228
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
229
 
230
- print("-"*(60 + len(" App Starting ")) + "\n")
231
 
232
  print("Launching Gradio Interface for Basic Agent Evaluation...")
233
  demo.launch(debug=True, share=False)
 
1
  import os
2
  import gradio as gr
 
 
3
  import pandas as pd
4
  import asyncio
5
+ from llama_index.embeddings.huggingface import HuggingFaceEmbedding
6
  from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec
7
  from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
8
  from llama_index.core.agent.workflow import AgentWorkflow
9
+ from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
10
  from llama_index.readers.web import SimpleWebPageReader
11
+ import requests
12
+ from huggingface_hub import InferenceClient
13
+ from llama_index.readers.wikipedia import WikipediaReader
14
  from llama_index.core.agent.workflow import (
15
  AgentInput,
16
  AgentOutput,
 
18
  ToolCallResult,
19
  AgentStream,
20
  )
21
+ import requests
22
+ from bs4 import BeautifulSoup
23
+ from urllib.parse import urljoin
24
 
25
  # (Keep Constants as is)
26
  # --- Constants ---
27
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
28
 
29
+
30
  # --- Basic Agent Definition ---
31
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
32
  class BasicAgent:
33
  def __init__(self):
34
  self.llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct")
35
+ self.vision_llm = HuggingFaceInferenceAPI(model_name="CohereLabs/aya-vision-32b")
36
+ self.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5")
37
+ self.search_client = DuckDuckGoSearchToolSpec()
38
+ self.wiki_reader = WikipediaReader()
39
  system_prompt = """
40
+ You are a helpful tool that uses the web to find out answers to specific questions in the manner that a human would.
41
+ Your answers should contain just ONE single word.
42
+
43
+ You have access to the following tools:
44
+
45
+ 1. search_web: This uses DuckDuckGo to search the web. It's useful when you need to find generic info or links to
46
+ web pages;
47
+
48
+ 2. search_wiki: Use this when you think searching Wikipedia directly is more useful;
49
+
50
+ 3. webpage_reader: Use this to extract content from web pages;
51
+
52
+ 4. describe_images: This tool will return descriptions of all the images on a web page. Use this to describe
53
+ images and figures;
54
+
55
+ 5. Use multiply_nums, divide_nums, add_nums and subtract_nums for basic math operations.
56
  """
57
+ self.agent = AgentWorkflow.from_tools_or_functions([self.search_web, self.search_wiki, self.webpage_reader,
58
+ self.describe_images, self.multiply_nums, self.divide_nums,
59
+ self.add_nums, self.subtract_nums],
60
+ llm=self.llm,
61
  system_prompt=system_prompt)
62
  print("BasicAgent initialized.")
63
+
64
  async def __call__(self, question: str) -> str:
65
  handler = self.agent.run(user_msg=question)
66
+ # async for event in handler.stream_events():
67
+ # if isinstance(event, AgentStream):
68
+ # print(event.delta, end="", flush=True)
69
+ # elif isinstance(event, ToolCallResult):
70
+ # print(event.tool_name) # the tool name
71
+ # print(event.tool_kwargs) # the tool kwargs
72
+ # print(event.tool_output) # the tool output
73
  response = await handler
74
  return str(response)
75
 
76
+ def extract_image_urls(self, page_url):
77
+ try:
78
+ # Send HTTP GET request to the page
79
+ response = requests.get(page_url)
80
+ response.raise_for_status() # Raise an error for bad status codes
81
+
82
+ # Parse HTML content
83
+ soup = BeautifulSoup(response.text, 'html.parser')
84
+
85
+ # Find all <img> tags
86
+ img_tags = soup.find_all('img')
87
+
88
+ # Extract and resolve image URLs
89
+ img_urls = []
90
+ for img in img_tags:
91
+ src = img.get('src')
92
+ if src:
93
+ # Make relative URLs absolute
94
+ full_url = urljoin(page_url, src)
95
+ img_urls.append(full_url)
96
+
97
+ return img_urls
98
+
99
+ except requests.RequestException as e:
100
+ print(f"Request failed: {e}")
101
+ return []
102
+
103
+ async def describe_images(self, webpage_url: str) -> str:
104
+ """Extracts and describes images from an input webpage url based on a query."""
105
+
106
+ image_urls = self.extract_image_urls(webpage_url)
107
+ print("image urls: ", image_urls)
108
+ if len(image_urls) == 0:
109
+ return "Looks like there are no images on this webpage"
110
+
111
+ docs = []
112
+ for image_url in image_urls:
113
+ messages = [
114
+ {
115
+ "role": "user",
116
+ "content": [
117
+ {
118
+ "type": "text",
119
+ "text": "Describe this image in one sentence."
120
+ },
121
+ {
122
+ "type": "image_url",
123
+ "image_url": {
124
+ "url": image_url
125
+ }
126
+ }
127
+ ]
128
+ }
129
+ ]
130
+
131
+ # print(messages)
132
+
133
+ client = InferenceClient(
134
+ provider="hyperbolic",
135
+ api_key=os.getenv('INFERENCE_KEY'),
136
+ )
137
+
138
+ try:
139
+ completion = client.chat.completions.create(
140
+ model="Qwen/Qwen2.5-VL-7B-Instruct",
141
+ messages=messages,
142
+ )
143
+
144
+ # print(completion.choices[0].message.content)
145
+ docs.append(completion.choices[0].message.content)
146
+ except:
147
+ continue
148
+ return str(docs)
149
+
150
+ async def search_wiki(self, query: str) -> str:
151
+ """Useful for browsing Wikipedia to look up specific info."""
152
+ reader = self.wiki_reader
153
+ documents = reader.load_data(pages=[query])
154
+ index = VectorStoreIndex.from_documents(documents, embed_model=self.embed_model)
155
+ search_res = index.as_query_engine(llm=self.llm).query(query)
156
+ return str(search_res)
157
+
158
+ async def search_web(self, query: str) -> str:
159
+ """Useful for using the web to answer questions. Keep the query very concise in order to get good results."""
160
+ client = self.search_client
161
+ search_res = client.duckduckgo_full_search(query)
162
+ return str(search_res)
163
+
164
+ async def webpage_reader(self, webpage_url: str) -> str:
165
+ """Useful for when you want to read and extract information from a specific webpage."""
166
+ documents = SimpleWebPageReader(html_to_text=True).load_data(
167
+ [webpage_url]
168
+ )
169
+ return str(documents)
170
+
171
+ async def multiply_nums(self, a: int, b: int) -> float:
172
+ """Useful for multiplying two numbers"""
173
+ return a * b
174
+
175
+ async def divide_nums(self, a: int, b: int) -> float:
176
+ """Useful for dividing two numbers"""
177
+ return a / b
178
+
179
+ async def add_nums(self, a: int, b: int) -> int:
180
+ """Useful for adding two numbers"""
181
+ return a + b
182
+
183
+ async def subtract_nums(self, a: int, b: int) -> int:
184
+ """Useful for subtracting two numbers"""
185
+ return a - b
186
+
187
 
188
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
189
  """
190
  Fetches all questions, runs the BasicAgent on them, submits all answers,
191
  and displays the results.
192
  """
193
  # --- Determine HF Space Runtime URL and Repo URL ---
194
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
195
 
196
  if profile:
197
+ username = f"{profile.username}"
198
  print(f"User logged in: {username}")
199
  else:
200
  print("User not logged in.")
 
221
  response.raise_for_status()
222
  questions_data = response.json()
223
  if not questions_data:
224
+ print("Fetched questions list is empty.")
225
+ return "Fetched questions list is empty or invalid format.", None
226
  print(f"Fetched {len(questions_data)} questions.")
227
  except requests.exceptions.RequestException as e:
228
  print(f"Error fetching questions: {e}")
229
  return f"Error fetching questions: {e}", None
230
  except requests.exceptions.JSONDecodeError as e:
231
+ print(f"Error decoding JSON response from questions endpoint: {e}")
232
+ print(f"Response text: {response.text[:500]}")
233
+ return f"Error decoding server response for questions: {e}", None
234
  except Exception as e:
235
  print(f"An unexpected error occurred fetching questions: {e}")
236
  return f"An unexpected error occurred fetching questions: {e}", None
 
242
  for item in questions_data:
243
  task_id = item.get("task_id")
244
  question_text = item.get("question")
245
+ question_text += "One-word answer only."
246
  if not task_id or question_text is None:
247
  print(f"Skipping item with missing task_id or question: {item}")
248
  continue
 
251
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
252
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
253
  except Exception as e:
254
+ print(f"Error running agent on task {task_id}: {e}")
255
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
256
 
257
  if not answers_payload:
258
  print("Agent did not produce any answers to submit.")
259
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
260
 
261
+ # 4. Prepare Submission
262
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
263
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
264
  print(status_update)
 
340
 
341
  if __name__ == "__main__":
342
  # agent = BasicAgent()
343
+ # while True:
344
+ # query = input("Ask a question here: ")
345
+ # answ = asyncio.run(agent(query))
346
 
347
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
348
  # Check for SPACE_HOST and SPACE_ID at startup for information
349
  space_host_startup = os.getenv("SPACE_HOST")
350
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
351
 
352
  if space_host_startup:
353
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
355
  else:
356
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
357
 
358
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
359
  print(f"✅ SPACE_ID found: {space_id_startup}")
360
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
361
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
362
  else:
363
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
364
 
365
+ print("-" * (60 + len(" App Starting ")) + "\n")
366
 
367
  print("Launching Gradio Interface for Basic Agent Evaluation...")
368
  demo.launch(debug=True, share=False)
requirements.txt CHANGED
@@ -1,9 +1,205 @@
1
- gradio
2
- requests
3
- llama-index
4
- llama-index-vector-stores-chroma
5
- llama-index-llms-huggingface-api
6
- llama-index-embeddings-huggingface
7
- llama-index-tools-duckduckgo
8
- llama-index-readers-web
9
- syncio
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ aiohappyeyeballs==2.6.1
3
+ aiohttp==3.12.2
4
+ aiosignal==1.3.2
5
+ aiosqlite==0.21.0
6
+ annotated-types==0.7.0
7
+ anyio==4.9.0
8
+ asgiref==3.8.1
9
+ attrs==25.3.0
10
+ Authlib==1.6.0
11
+ backoff==2.2.1
12
+ banks==2.1.2
13
+ bcrypt==4.3.0
14
+ beautifulsoup4==4.13.4
15
+ build==1.2.2.post1
16
+ cachetools==5.5.2
17
+ certifi==2025.4.26
18
+ cffi==1.17.1
19
+ charset-normalizer==3.4.2
20
+ chromadb==1.0.10
21
+ chromedriver-autoinstaller==0.6.4
22
+ click==8.2.1
23
+ colorama==0.4.6
24
+ coloredlogs==15.0.1
25
+ cryptography==45.0.3
26
+ cssselect==1.3.0
27
+ dataclasses-json==0.6.7
28
+ defusedxml==0.7.1
29
+ Deprecated==1.2.18
30
+ dirtyjson==1.0.8
31
+ distro==1.9.0
32
+ duckduckgo_search==6.4.2
33
+ durationpy==0.10
34
+ fastapi==0.115.9
35
+ feedfinder2==0.0.4
36
+ feedparser==6.0.11
37
+ ffmpy==0.5.0
38
+ filelock==3.18.0
39
+ filetype==1.2.0
40
+ flatbuffers==25.2.10
41
+ frozenlist==1.6.0
42
+ fsspec==2025.5.1
43
+ google-auth==2.40.2
44
+ googleapis-common-protos==1.70.0
45
+ gradio==5.31.0
46
+ gradio_client==1.10.1
47
+ greenlet==3.2.2
48
+ griffe==1.7.3
49
+ groovy==0.1.2
50
+ grpcio==1.71.0
51
+ h11==0.16.0
52
+ hf-xet==1.1.2
53
+ html2text==2024.2.26
54
+ httpcore==1.0.9
55
+ httptools==0.6.4
56
+ httpx==0.28.1
57
+ huggingface-hub==0.32.2
58
+ humanfriendly==10.0
59
+ idna==3.10
60
+ importlib_metadata==8.6.1
61
+ importlib_resources==6.5.2
62
+ itsdangerous==2.2.0
63
+ jieba3k==0.35.1
64
+ Jinja2==3.1.6
65
+ jiter==0.10.0
66
+ joblib==1.5.1
67
+ jsonschema==4.24.0
68
+ jsonschema-specifications==2025.4.1
69
+ kubernetes==32.0.1
70
+ llama-cloud==0.1.22
71
+ llama-cloud-services==0.6.23
72
+ llama-index==0.12.37
73
+ llama-index-agent-openai==0.4.8
74
+ llama-index-cli==0.4.1
75
+ llama-index-core==0.12.37
76
+ llama-index-embeddings-huggingface==0.5.4
77
+ llama-index-embeddings-openai==0.3.1
78
+ llama-index-indices-managed-llama-cloud==0.6.11
79
+ llama-index-llms-huggingface-api==0.4.3
80
+ llama-index-llms-openai==0.3.44
81
+ llama-index-multi-modal-llms-openai==0.4.3
82
+ llama-index-program-openai==0.3.1
83
+ llama-index-question-gen-openai==0.3.0
84
+ llama-index-readers-file==0.4.8
85
+ llama-index-readers-llama-parse==0.4.0
86
+ llama-index-readers-web==0.4.1
87
+ llama-index-readers-wikipedia==0.3.0
88
+ llama-index-tools-duckduckgo==0.3.0
89
+ llama-index-vector-stores-chroma==0.4.1
90
+ llama-parse==0.6.23
91
+ lxml==5.4.0
92
+ lxml_html_clean==0.4.2
93
+ markdown-it-py==3.0.0
94
+ markdownify==1.1.0
95
+ MarkupSafe==3.0.2
96
+ marshmallow==3.26.1
97
+ mdurl==0.1.2
98
+ mmh3==5.1.0
99
+ mpmath==1.3.0
100
+ multidict==6.4.4
101
+ mypy_extensions==1.1.0
102
+ nest-asyncio==1.6.0
103
+ networkx==3.4.2
104
+ newspaper3k==0.2.8
105
+ nltk==3.9.1
106
+ numpy==1.26.4
107
+ oauthlib==3.2.2
108
+ onnxruntime==1.16.3
109
+ openai==1.82.0
110
+ opentelemetry-api==1.33.1
111
+ opentelemetry-exporter-otlp-proto-common==1.33.1
112
+ opentelemetry-exporter-otlp-proto-grpc==1.33.1
113
+ opentelemetry-instrumentation==0.54b1
114
+ opentelemetry-instrumentation-asgi==0.54b1
115
+ opentelemetry-instrumentation-fastapi==0.54b1
116
+ opentelemetry-proto==1.33.1
117
+ opentelemetry-sdk==1.33.1
118
+ opentelemetry-semantic-conventions==0.54b1
119
+ opentelemetry-util-http==0.54b1
120
+ orjson==3.10.18
121
+ outcome==1.3.0.post0
122
+ overrides==7.7.0
123
+ oxylabs==2.0.0
124
+ packaging==25.0
125
+ pandas==2.2.3
126
+ pillow==11.2.1
127
+ platformdirs==4.3.8
128
+ playwright==1.52.0
129
+ posthog==4.2.0
130
+ primp==0.15.0
131
+ propcache==0.3.1
132
+ protobuf==5.29.4
133
+ pyasn1==0.6.1
134
+ pyasn1_modules==0.4.2
135
+ pycparser==2.22
136
+ pydantic==2.11.5
137
+ pydantic_core==2.33.2
138
+ pydub==0.25.1
139
+ pyee==13.0.0
140
+ Pygments==2.19.1
141
+ pypdf==5.5.0
142
+ PyPika==0.48.9
143
+ pyproject_hooks==1.2.0
144
+ PySocks==1.7.1
145
+ python-dateutil==2.9.0.post0
146
+ python-dotenv==1.1.0
147
+ python-multipart==0.0.20
148
+ pytz==2025.2
149
+ PyYAML==6.0.2
150
+ referencing==0.36.2
151
+ regex==2024.11.6
152
+ requests==2.32.3
153
+ requests-file==2.1.0
154
+ requests-oauthlib==2.0.0
155
+ rich==14.0.0
156
+ rpds-py==0.25.1
157
+ rsa==4.9.1
158
+ ruff==0.11.11
159
+ safehttpx==0.1.6
160
+ safetensors==0.5.3
161
+ scikit-learn==1.6.1
162
+ scipy==1.15.3
163
+ selenium==4.33.0
164
+ semantic-version==2.10.0
165
+ sentence-transformers==4.1.0
166
+ sgmllib3k==1.0.0
167
+ shellingham==1.5.4
168
+ six==1.17.0
169
+ sniffio==1.3.1
170
+ sortedcontainers==2.4.0
171
+ soupsieve==2.7
172
+ spider-client==0.0.27
173
+ SQLAlchemy==2.0.41
174
+ starlette==0.45.3
175
+ striprtf==0.0.26
176
+ sympy==1.14.0
177
+ syncio==0.0.4
178
+ tenacity==9.1.2
179
+ threadpoolctl==3.6.0
180
+ tiktoken==0.9.0
181
+ tinysegmenter==0.3
182
+ tldextract==5.3.0
183
+ tokenizers==0.15.2
184
+ tomlkit==0.13.2
185
+ torch==2.2.2
186
+ tqdm==4.67.1
187
+ transformers==4.36.2
188
+ trio==0.30.0
189
+ trio-websocket==0.12.2
190
+ typer==0.16.0
191
+ typing-inspect==0.9.0
192
+ typing-inspection==0.4.1
193
+ typing_extensions==4.13.2
194
+ tzdata==2025.2
195
+ urllib3==2.4.0
196
+ uvicorn==0.34.2
197
+ uvloop==0.21.0
198
+ watchfiles==1.0.5
199
+ websocket-client==1.8.0
200
+ websockets==15.0.1
201
+ wikipedia==1.4.0
202
+ wrapt==1.17.2
203
+ wsproto==1.2.0
204
+ yarl==1.20.0
205
+ zipp==3.22.0