CoACT initialize (#292)
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from .google_search import GoogleSearchTool
|
||||
from .youtube_search import YoutubeSearchTool
|
||||
|
||||
__all__ = ["GoogleSearchTool", "YoutubeSearchTool"]
|
||||
@@ -0,0 +1,93 @@
|
||||
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Annotated, Any, Optional
|
||||
|
||||
from ....doc_utils import export_module
|
||||
from ....import_utils import optional_import_block, require_optional_import
|
||||
from ... import Depends, Tool
|
||||
from ...dependency_injection import on
|
||||
|
||||
with optional_import_block():
|
||||
from googleapiclient.discovery import build
|
||||
|
||||
|
||||
@require_optional_import(
|
||||
[
|
||||
"googleapiclient",
|
||||
],
|
||||
"google-search",
|
||||
)
|
||||
def _execute_query(query: str, search_api_key: str, search_engine_id: str, num_results: int) -> Any:
|
||||
service = build("customsearch", "v1", developerKey=search_api_key)
|
||||
return service.cse().list(q=query, cx=search_engine_id, num=num_results).execute()
|
||||
|
||||
|
||||
def _google_search(
|
||||
query: str,
|
||||
search_api_key: str,
|
||||
search_engine_id: str,
|
||||
num_results: int,
|
||||
) -> list[dict[str, Any]]:
|
||||
res = _execute_query(
|
||||
query=query, search_api_key=search_api_key, search_engine_id=search_engine_id, num_results=num_results
|
||||
)
|
||||
|
||||
return [
|
||||
{"title": item.get("title", ""), "link": item.get("link", ""), "snippet": item.get("snippet", "")}
|
||||
for item in res.get("items", [])
|
||||
]
|
||||
|
||||
|
||||
@export_module("autogen.tools.experimental")
|
||||
class GoogleSearchTool(Tool):
|
||||
"""GoogleSearchTool is a tool that uses the Google Search API to perform a search."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
search_api_key: Optional[str] = None,
|
||||
search_engine_id: Optional[str] = None,
|
||||
use_internal_llm_tool_if_available: bool = True,
|
||||
):
|
||||
"""GoogleSearchTool is a tool that uses the Google Search API to perform a search.
|
||||
|
||||
Args:
|
||||
search_api_key: The API key for the Google Search API.
|
||||
search_engine_id: The search engine ID for the Google Search API.
|
||||
use_internal_llm_tool_if_available: Whether to use the predefined (e.g. Gemini GenaAI) search tool. Currently, this can only be used for agents with the Gemini (GenAI) configuration.
|
||||
"""
|
||||
self.search_api_key = search_api_key
|
||||
self.search_engine_id = search_engine_id
|
||||
self.use_internal_llm_tool_if_available = use_internal_llm_tool_if_available
|
||||
|
||||
if not use_internal_llm_tool_if_available and (search_api_key is None or search_engine_id is None):
|
||||
raise ValueError(
|
||||
"search_api_key and search_engine_id must be provided if use_internal_llm_tool_if_available is False"
|
||||
)
|
||||
|
||||
if use_internal_llm_tool_if_available and (search_api_key is not None or search_engine_id is not None):
|
||||
logging.warning("search_api_key and search_engine_id will be ignored if internal LLM tool is available")
|
||||
|
||||
def google_search(
|
||||
query: Annotated[str, "The search query."],
|
||||
search_api_key: Annotated[Optional[str], Depends(on(search_api_key))],
|
||||
search_engine_id: Annotated[Optional[str], Depends(on(search_engine_id))],
|
||||
num_results: Annotated[int, "The number of results to return."] = 10,
|
||||
) -> list[dict[str, Any]]:
|
||||
if search_api_key is None or search_engine_id is None:
|
||||
raise ValueError(
|
||||
"Your LLM is not configured to use prebuilt google-search tool.\n"
|
||||
"Please provide search_api_key and search_engine_id.\n"
|
||||
)
|
||||
return _google_search(query, search_api_key, search_engine_id, num_results)
|
||||
|
||||
super().__init__(
|
||||
# GeminiClient will look for a tool with the name "prebuilt_google_search"
|
||||
name="prebuilt_google_search" if use_internal_llm_tool_if_available else "google_search",
|
||||
description="Use the Google Search API to perform a search.",
|
||||
func_or_tool=google_search,
|
||||
)
|
||||
@@ -0,0 +1,181 @@
|
||||
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Annotated, Any, Dict, List, Optional
|
||||
|
||||
from ....doc_utils import export_module
|
||||
from ....import_utils import optional_import_block, require_optional_import
|
||||
from ... import Depends, Tool
|
||||
from ...dependency_injection import on
|
||||
|
||||
with optional_import_block():
|
||||
import googleapiclient.errors
|
||||
from googleapiclient.discovery import build
|
||||
|
||||
|
||||
@require_optional_import(
|
||||
["googleapiclient"],
|
||||
"google-search",
|
||||
)
|
||||
def _execute_search_query(query: str, youtube_api_key: str, max_results: int) -> Any:
|
||||
"""Execute a YouTube search query using the YouTube Data API.
|
||||
|
||||
Args:
|
||||
query: The search query string.
|
||||
youtube_api_key: The API key for the YouTube Data API.
|
||||
max_results: The maximum number of results to return.
|
||||
|
||||
Returns:
|
||||
The search response from the YouTube Data API.
|
||||
"""
|
||||
youtube = build("youtube", "v3", developerKey=youtube_api_key)
|
||||
|
||||
try:
|
||||
search_response = (
|
||||
youtube.search().list(q=query, part="id,snippet", maxResults=max_results, type="video").execute()
|
||||
)
|
||||
|
||||
return search_response
|
||||
except googleapiclient.errors.HttpError as e:
|
||||
logging.error(f"An HTTP error occurred: {e}")
|
||||
raise
|
||||
|
||||
|
||||
@require_optional_import(
|
||||
["googleapiclient"],
|
||||
"google-search",
|
||||
)
|
||||
def _get_video_details(video_ids: List[str], youtube_api_key: str) -> Any:
|
||||
"""Get detailed information about specific YouTube videos.
|
||||
|
||||
Args:
|
||||
video_ids: List of YouTube video IDs.
|
||||
youtube_api_key: The API key for the YouTube Data API.
|
||||
|
||||
Returns:
|
||||
The video details response from the YouTube Data API.
|
||||
"""
|
||||
if not video_ids:
|
||||
return {"items": []}
|
||||
|
||||
youtube = build("youtube", "v3", developerKey=youtube_api_key)
|
||||
|
||||
try:
|
||||
videos_response = (
|
||||
youtube.videos().list(id=",".join(video_ids), part="snippet,contentDetails,statistics").execute()
|
||||
)
|
||||
|
||||
return videos_response
|
||||
except googleapiclient.errors.HttpError as e:
|
||||
logging.error(f"An HTTP error occurred: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def _youtube_search(
|
||||
query: str,
|
||||
youtube_api_key: str,
|
||||
max_results: int,
|
||||
include_video_details: bool = True,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search YouTube videos based on a query.
|
||||
|
||||
Args:
|
||||
query: The search query string.
|
||||
youtube_api_key: The API key for the YouTube Data API.
|
||||
max_results: The maximum number of results to return.
|
||||
include_video_details: Whether to include detailed video information.
|
||||
|
||||
Returns:
|
||||
A list of dictionaries containing information about the videos.
|
||||
"""
|
||||
search_response = _execute_search_query(query=query, youtube_api_key=youtube_api_key, max_results=max_results)
|
||||
|
||||
results = []
|
||||
video_ids = []
|
||||
|
||||
# Extract basic info from search results
|
||||
for item in search_response.get("items", []):
|
||||
if item["id"]["kind"] == "youtube#video":
|
||||
video_ids.append(item["id"]["videoId"])
|
||||
video_info = {
|
||||
"title": item["snippet"]["title"],
|
||||
"description": item["snippet"]["description"],
|
||||
"publishedAt": item["snippet"]["publishedAt"],
|
||||
"channelTitle": item["snippet"]["channelTitle"],
|
||||
"videoId": item["id"]["videoId"],
|
||||
"url": f"https://www.youtube.com/watch?v={item['id']['videoId']}",
|
||||
}
|
||||
results.append(video_info)
|
||||
|
||||
# If detailed info requested, get it
|
||||
if include_video_details and video_ids:
|
||||
video_details = _get_video_details(video_ids, youtube_api_key)
|
||||
|
||||
# Create a mapping of videoId to details
|
||||
details_map = {item["id"]: item for item in video_details.get("items", [])}
|
||||
|
||||
# Update results with additional details
|
||||
for result in results:
|
||||
video_id = result["videoId"]
|
||||
if video_id in details_map:
|
||||
details = details_map[video_id]
|
||||
result.update({
|
||||
"viewCount": details["statistics"].get("viewCount"),
|
||||
"likeCount": details["statistics"].get("likeCount"),
|
||||
"commentCount": details["statistics"].get("commentCount"),
|
||||
"duration": details["contentDetails"].get("duration"),
|
||||
"definition": details["contentDetails"].get("definition"),
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@export_module("autogen.tools.experimental")
|
||||
class YoutubeSearchTool(Tool):
|
||||
"""YoutubeSearchTool is a tool that uses the YouTube Data API to search for videos."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
youtube_api_key: Optional[str] = None,
|
||||
):
|
||||
"""Initialize a YouTube search tool.
|
||||
|
||||
Args:
|
||||
youtube_api_key: The API key for the YouTube Data API.
|
||||
"""
|
||||
self.youtube_api_key = youtube_api_key
|
||||
|
||||
if youtube_api_key is None:
|
||||
raise ValueError("youtube_api_key must be provided")
|
||||
|
||||
def youtube_search(
|
||||
query: Annotated[str, "The search query for YouTube videos."],
|
||||
youtube_api_key: Annotated[str, Depends(on(youtube_api_key))],
|
||||
max_results: Annotated[int, "The maximum number of results to return."] = 5,
|
||||
include_video_details: Annotated[bool, "Whether to include detailed video information."] = True,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search for YouTube videos based on a query.
|
||||
|
||||
Args:
|
||||
query: The search query string.
|
||||
youtube_api_key: The API key for the YouTube Data API.
|
||||
max_results: The maximum number of results to return.
|
||||
include_video_details: Whether to include detailed video information.
|
||||
|
||||
Returns:
|
||||
A list of dictionaries containing information about the videos.
|
||||
"""
|
||||
if youtube_api_key is None:
|
||||
raise ValueError("YouTube API key is required")
|
||||
|
||||
return _youtube_search(query, youtube_api_key, max_results, include_video_details)
|
||||
|
||||
super().__init__(
|
||||
name="youtube_search",
|
||||
description="Search for YouTube videos based on a query, optionally including detailed information.",
|
||||
func_or_tool=youtube_search,
|
||||
)
|
||||
Reference in New Issue
Block a user