3v324v23's picture
Зафиксирована рабочая версия TEN-Agent для HuggingFace Space
87337b1
#
#
# Agora Real Time Engagement
# Created by Wei Hu in 2024-08.
# Copyright (c) 2024 Agora IO. All rights reserved.
#
#
import json
import aiohttp
from typing import Any, List
from ten import (
Cmd,
)
from ten.async_ten_env import AsyncTenEnv
from ten_ai_base.config import BaseConfig
from ten_ai_base.types import LLMToolMetadata, LLMToolMetadataParameter, LLMToolResult
from ten_ai_base.llm_tool import AsyncLLMToolBaseExtension
CMD_TOOL_REGISTER = "tool_register"
CMD_TOOL_CALL = "tool_call"
CMD_PROPERTY_NAME = "name"
CMD_PROPERTY_ARGS = "args"
TOOL_REGISTER_PROPERTY_NAME = "name"
TOOL_REGISTER_PROPERTY_DESCRIPTON = "description"
TOOL_REGISTER_PROPERTY_PARAMETERS = "parameters"
TOOL_CALLBACK = "callback"
TOOL_NAME = "bing_search"
TOOL_DESCRIPTION = "Use Bing.com to search for latest information. Call this function if you are not sure about the answer."
TOOL_PARAMETERS = {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query to call Bing Search.",
}
},
"required": ["query"],
}
PROPERTY_API_KEY = "api_key" # Required
DEFAULT_BING_SEARCH_ENDPOINT = "https://api.bing.microsoft.com/v7.0/search"
# BING_SEARCH_ENDPOINT is the default endpoint for Bing Web Search API.
# Currently There are two web-based Bing Search services available on Azure,
# i.e. Bing Web Search[1] and Bing Custom Search[2]. Compared to Bing Custom Search,
# Both services that provides a wide range of search results, while Bing Custom
# Search requires you to provide an additional custom search instance, `customConfig`.
# Both services are available for BingSearchAPIWrapper.
# History of Azure Bing Search API:
# Before shown in Azure Marketplace as a separate service, Bing Search APIs were
# part of Azure Cognitive Services, the endpoint of which is unique, and the user
# must specify the endpoint when making a request. After transitioning to Azure
# Marketplace, the endpoint is standardized and the user does not need to specify
# the endpoint[3].
# Reference:
# 1. https://learn.microsoft.com/en-us/bing/search-apis/bing-web-search/overview
# 2. https://learn.microsoft.com/en-us/bing/search-apis/bing-custom-search/overview
# 3. https://azure.microsoft.com/en-in/updates/bing-search-apis-will-transition-from-azure-cognitive-services-to-azure-marketplace-on-31-october-2023/
class BingSearchToolConfig(BaseConfig):
api_key: str = ""
class BingSearchToolExtension(AsyncLLMToolBaseExtension):
def __init__(self, name: str) -> None:
super().__init__(name)
self.session = None
self.config = None
self.k = 10
async def on_init(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_init")
self.session = aiohttp.ClientSession()
await super().on_init(ten_env)
async def on_start(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_start")
await super().on_start(ten_env)
self.config = await BingSearchToolConfig.create_async(ten_env=ten_env)
if not self.config.api_key:
ten_env.log_info("API key is missing, exiting on_start")
return
async def on_stop(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_stop")
# clean up resources
if self.session and not self.session.closed:
await self.session.close()
self.session = None # Ensure it can't be reused accidentally
async def on_cmd(self, ten_env: AsyncTenEnv, cmd: Cmd) -> None:
cmd_name = cmd.get_name()
ten_env.log_debug("on_cmd name {}".format(cmd_name))
await super().on_cmd(ten_env, cmd)
def get_tool_metadata(self, ten_env: AsyncTenEnv) -> list[LLMToolMetadata]:
return [
LLMToolMetadata(
name=TOOL_NAME,
description=TOOL_DESCRIPTION,
parameters=[
LLMToolMetadataParameter(
name="query",
type="string",
description="The search query to call Bing Search.",
required=True,
),
],
)
]
async def run_tool(
self, ten_env: AsyncTenEnv, name: str, args: dict
) -> LLMToolResult | None:
if name == TOOL_NAME:
result = await self._do_search(ten_env, args)
# result = LLMCompletionContentItemText(text="I see something")
return {"content": json.dumps(result)}
async def _do_search(self, ten_env: AsyncTenEnv, args: dict) -> Any:
if "query" not in args:
raise ValueError("Failed to get property")
query = args["query"]
snippets = []
results = await self._bing_search_results(ten_env, query, count=self.k)
if len(results) == 0:
return "No good Bing Search Result was found"
for result in results:
snippets.append(result["snippet"])
return snippets
async def _initialize_session(self, ten_env: AsyncTenEnv):
if self.session is None or self.session.closed:
ten_env.log_debug("Initializing new session")
self.session = aiohttp.ClientSession()
async def _bing_search_results(self, ten_env: AsyncTenEnv, search_term: str, count: int) -> List[dict]:
await self._initialize_session(ten_env)
headers = {"Ocp-Apim-Subscription-Key": self.config.api_key}
params = {
"q": search_term,
"count": count,
"textDecorations": "true",
"textFormat": "HTML",
}
async with self.session as session:
async with session.get(
DEFAULT_BING_SEARCH_ENDPOINT, headers=headers, params=params
) as response:
response.raise_for_status()
search_results = await response.json()
if "webPages" in search_results:
return search_results["webPages"]["value"]
return []