initial commit

This commit is contained in:
2026-05-11 12:36:20 +05:30
commit 384cbe8019
15377 changed files with 2360544 additions and 0 deletions

View File

@@ -0,0 +1,664 @@
"""**Tools** are classes that an Agent uses to interact with the world.
Each tool has a **description**. Agent uses the description to choose the right
tool for the job.
**Class hierarchy:**
.. code-block::
ToolMetaclass --> BaseTool --> <name>Tool # Examples: AIPluginTool, BaseGraphQLTool
<name> # Examples: BraveSearch, HumanInputRun
**Main helpers:**
.. code-block::
CallbackManagerForToolRun, AsyncCallbackManagerForToolRun
"""
import importlib
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from langchain_core.tools import (
BaseTool as BaseTool,
)
from langchain_core.tools import (
StructuredTool as StructuredTool,
)
from langchain_core.tools import (
Tool as Tool,
)
from langchain_core.tools.convert import tool as tool
from langchain_community.tools.ainetwork.app import (
AINAppOps,
)
from langchain_community.tools.ainetwork.owner import (
AINOwnerOps,
)
from langchain_community.tools.ainetwork.rule import (
AINRuleOps,
)
from langchain_community.tools.ainetwork.transfer import (
AINTransfer,
)
from langchain_community.tools.ainetwork.value import (
AINValueOps,
)
from langchain_community.tools.arxiv.tool import (
ArxivQueryRun,
)
from langchain_community.tools.asknews.tool import (
AskNewsSearch,
)
from langchain_community.tools.azure_ai_services import (
AzureAiServicesDocumentIntelligenceTool,
AzureAiServicesImageAnalysisTool,
AzureAiServicesSpeechToTextTool,
AzureAiServicesTextAnalyticsForHealthTool,
AzureAiServicesTextToSpeechTool,
)
from langchain_community.tools.azure_cognitive_services import (
AzureCogsFormRecognizerTool,
AzureCogsImageAnalysisTool,
AzureCogsSpeech2TextTool,
AzureCogsText2SpeechTool,
AzureCogsTextAnalyticsHealthTool,
)
from langchain_community.tools.bearly.tool import (
BearlyInterpreterTool,
)
from langchain_community.tools.bing_search.tool import (
BingSearchResults,
BingSearchRun,
)
from langchain_community.tools.brave_search.tool import (
BraveSearch,
)
from langchain_community.tools.cassandra_database.tool import (
GetSchemaCassandraDatabaseTool, # noqa: F401
GetTableDataCassandraDatabaseTool, # noqa: F401
QueryCassandraDatabaseTool, # noqa: F401
)
from langchain_community.tools.cogniswitch.tool import (
CogniswitchKnowledgeRequest,
CogniswitchKnowledgeSourceFile,
CogniswitchKnowledgeSourceURL,
CogniswitchKnowledgeStatus,
)
from langchain_community.tools.connery import (
ConneryAction,
)
from langchain_community.tools.convert_to_openai import (
format_tool_to_openai_function,
)
from langchain_community.tools.dataherald import DataheraldTextToSQL
from langchain_community.tools.ddg_search.tool import (
DuckDuckGoSearchResults,
DuckDuckGoSearchRun,
)
from langchain_community.tools.e2b_data_analysis.tool import (
E2BDataAnalysisTool,
)
from langchain_community.tools.edenai import (
EdenAiExplicitImageTool,
EdenAiObjectDetectionTool,
EdenAiParsingIDTool,
EdenAiParsingInvoiceTool,
EdenAiSpeechToTextTool,
EdenAiTextModerationTool,
EdenAiTextToSpeechTool,
EdenaiTool,
)
from langchain_community.tools.eleven_labs.text2speech import (
ElevenLabsText2SpeechTool,
)
from langchain_community.tools.file_management import (
CopyFileTool,
DeleteFileTool,
FileSearchTool,
ListDirectoryTool,
MoveFileTool,
ReadFileTool,
WriteFileTool,
)
from langchain_community.tools.financial_datasets.balance_sheets import (
BalanceSheets,
)
from langchain_community.tools.financial_datasets.cash_flow_statements import (
CashFlowStatements,
)
from langchain_community.tools.financial_datasets.income_statements import (
IncomeStatements,
)
from langchain_community.tools.gmail import (
GmailCreateDraft,
GmailGetMessage,
GmailGetThread,
GmailSearch,
GmailSendMessage,
)
from langchain_community.tools.google_books import (
GoogleBooksQueryRun,
)
from langchain_community.tools.google_cloud.texttospeech import (
GoogleCloudTextToSpeechTool,
)
from langchain_community.tools.google_places.tool import (
GooglePlacesTool,
)
from langchain_community.tools.google_search.tool import (
GoogleSearchResults,
GoogleSearchRun,
)
from langchain_community.tools.google_serper.tool import (
GoogleSerperResults,
GoogleSerperRun,
)
from langchain_community.tools.graphql.tool import (
BaseGraphQLTool,
)
from langchain_community.tools.human.tool import (
HumanInputRun,
)
from langchain_community.tools.ifttt import (
IFTTTWebhook,
)
from langchain_community.tools.interaction.tool import (
StdInInquireTool,
)
from langchain_community.tools.jina_search.tool import JinaSearch
from langchain_community.tools.jira.tool import (
JiraAction,
)
from langchain_community.tools.json.tool import (
JsonGetValueTool,
JsonListKeysTool,
)
from langchain_community.tools.merriam_webster.tool import (
MerriamWebsterQueryRun,
)
from langchain_community.tools.metaphor_search import (
MetaphorSearchResults,
)
from langchain_community.tools.mojeek_search.tool import (
MojeekSearch,
)
from langchain_community.tools.nasa.tool import (
NasaAction,
)
from langchain_community.tools.office365.create_draft_message import (
O365CreateDraftMessage,
)
from langchain_community.tools.office365.events_search import (
O365SearchEvents,
)
from langchain_community.tools.office365.messages_search import (
O365SearchEmails,
)
from langchain_community.tools.office365.send_event import (
O365SendEvent,
)
from langchain_community.tools.office365.send_message import (
O365SendMessage,
)
from langchain_community.tools.office365.utils import (
authenticate,
)
from langchain_community.tools.openapi.utils.api_models import (
APIOperation,
)
from langchain_community.tools.openapi.utils.openapi_utils import (
OpenAPISpec,
)
from langchain_community.tools.openweathermap.tool import (
OpenWeatherMapQueryRun,
)
from langchain_community.tools.playwright import (
ClickTool,
CurrentWebPageTool,
ExtractHyperlinksTool,
ExtractTextTool,
GetElementsTool,
NavigateBackTool,
NavigateTool,
)
from langchain_community.tools.plugin import (
AIPluginTool,
)
from langchain_community.tools.polygon.aggregates import (
PolygonAggregates,
)
from langchain_community.tools.polygon.financials import (
PolygonFinancials,
)
from langchain_community.tools.polygon.last_quote import (
PolygonLastQuote,
)
from langchain_community.tools.polygon.ticker_news import (
PolygonTickerNews,
)
from langchain_community.tools.powerbi.tool import (
InfoPowerBITool,
ListPowerBITool,
QueryPowerBITool,
)
from langchain_community.tools.pubmed.tool import (
PubmedQueryRun,
)
from langchain_community.tools.reddit_search.tool import (
RedditSearchRun,
RedditSearchSchema,
)
from langchain_community.tools.requests.tool import (
BaseRequestsTool,
RequestsDeleteTool,
RequestsGetTool,
RequestsPatchTool,
RequestsPostTool,
RequestsPutTool,
)
from langchain_community.tools.scenexplain.tool import (
SceneXplainTool,
)
from langchain_community.tools.searchapi.tool import (
SearchAPIResults,
SearchAPIRun,
)
from langchain_community.tools.searx_search.tool import (
SearxSearchResults,
SearxSearchRun,
)
from langchain_community.tools.shell.tool import (
ShellTool,
)
from langchain_community.tools.slack.get_channel import (
SlackGetChannel,
)
from langchain_community.tools.slack.get_message import (
SlackGetMessage,
)
from langchain_community.tools.slack.schedule_message import (
SlackScheduleMessage,
)
from langchain_community.tools.slack.send_message import (
SlackSendMessage,
)
from langchain_community.tools.sleep.tool import (
SleepTool,
)
from langchain_community.tools.spark_sql.tool import (
BaseSparkSQLTool,
InfoSparkSQLTool,
ListSparkSQLTool,
QueryCheckerTool,
QuerySparkSQLTool,
)
from langchain_community.tools.sql_database.tool import (
BaseSQLDatabaseTool,
InfoSQLDatabaseTool,
ListSQLDatabaseTool,
QuerySQLCheckerTool,
QuerySQLDataBaseTool,
QuerySQLDatabaseTool,
)
from langchain_community.tools.stackexchange.tool import (
StackExchangeTool,
)
from langchain_community.tools.steam.tool import (
SteamWebAPIQueryRun,
)
from langchain_community.tools.steamship_image_generation import (
SteamshipImageGenerationTool,
)
from langchain_community.tools.tavily_search import (
TavilyAnswer,
TavilySearchResults,
)
from langchain_community.tools.vectorstore.tool import (
VectorStoreQATool,
VectorStoreQAWithSourcesTool,
)
from langchain_community.tools.wikipedia.tool import (
WikipediaQueryRun,
)
from langchain_community.tools.wolfram_alpha.tool import (
WolframAlphaQueryRun,
)
from langchain_community.tools.yahoo_finance_news import (
YahooFinanceNewsTool,
)
from langchain_community.tools.you.tool import (
YouSearchTool,
)
from langchain_community.tools.youtube.search import (
YouTubeSearchTool,
)
from langchain_community.tools.zapier.tool import (
ZapierNLAListActions,
ZapierNLARunAction,
)
from langchain_community.tools.zenguard.tool import (
Detector,
ZenGuardInput,
ZenGuardTool,
)
__all__ = [
"BaseTool",
"Tool",
"tool",
"StructuredTool",
"AINAppOps",
"AINOwnerOps",
"AINRuleOps",
"AINTransfer",
"AINValueOps",
"AIPluginTool",
"APIOperation",
"ArxivQueryRun",
"AskNewsSearch",
"AzureAiServicesDocumentIntelligenceTool",
"AzureAiServicesImageAnalysisTool",
"AzureAiServicesSpeechToTextTool",
"AzureAiServicesTextAnalyticsForHealthTool",
"AzureAiServicesTextToSpeechTool",
"AzureCogsFormRecognizerTool",
"AzureCogsImageAnalysisTool",
"AzureCogsSpeech2TextTool",
"AzureCogsText2SpeechTool",
"AzureCogsTextAnalyticsHealthTool",
"BalanceSheets",
"BaseGraphQLTool",
"BaseRequestsTool",
"BaseSQLDatabaseTool",
"BaseSparkSQLTool",
"BearlyInterpreterTool",
"BingSearchResults",
"BingSearchRun",
"BraveSearch",
"CashFlowStatements",
"ClickTool",
"CogniswitchKnowledgeRequest",
"CogniswitchKnowledgeSourceFile",
"CogniswitchKnowledgeSourceURL",
"CogniswitchKnowledgeStatus",
"ConneryAction",
"CopyFileTool",
"CurrentWebPageTool",
"DeleteFileTool",
"DataheraldTextToSQL",
"DuckDuckGoSearchResults",
"DuckDuckGoSearchRun",
"E2BDataAnalysisTool",
"EdenAiExplicitImageTool",
"EdenAiObjectDetectionTool",
"EdenAiParsingIDTool",
"EdenAiParsingInvoiceTool",
"EdenAiSpeechToTextTool",
"EdenAiTextModerationTool",
"EdenAiTextToSpeechTool",
"EdenaiTool",
"ElevenLabsText2SpeechTool",
"ExtractHyperlinksTool",
"ExtractTextTool",
"FileSearchTool",
"GetElementsTool",
"GmailCreateDraft",
"GmailGetMessage",
"GmailGetThread",
"GmailSearch",
"GmailSendMessage",
"GoogleBooksQueryRun",
"GoogleCloudTextToSpeechTool",
"GooglePlacesTool",
"GoogleSearchResults",
"GoogleSearchRun",
"GoogleSerperResults",
"GoogleSerperRun",
"HumanInputRun",
"IFTTTWebhook",
"IncomeStatements",
"InfoPowerBITool",
"InfoSQLDatabaseTool",
"InfoSparkSQLTool",
"JiraAction",
"JinaSearch",
"JsonGetValueTool",
"JsonListKeysTool",
"ListDirectoryTool",
"ListPowerBITool",
"ListSQLDatabaseTool",
"ListSparkSQLTool",
"MerriamWebsterQueryRun",
"MetaphorSearchResults",
"MojeekSearch",
"MoveFileTool",
"NasaAction",
"NavigateBackTool",
"NavigateTool",
"O365CreateDraftMessage",
"O365SearchEmails",
"O365SearchEvents",
"O365SendEvent",
"O365SendMessage",
"OpenAPISpec",
"OpenWeatherMapQueryRun",
"PolygonAggregates",
"PolygonFinancials",
"PolygonLastQuote",
"PolygonTickerNews",
"PubmedQueryRun",
"QueryCheckerTool",
"QueryPowerBITool",
"QuerySQLCheckerTool",
"QuerySQLDatabaseTool",
"QuerySQLDataBaseTool", # Legacy, kept for backwards compatibility.
"QuerySparkSQLTool",
"ReadFileTool",
"RedditSearchRun",
"RedditSearchSchema",
"RequestsDeleteTool",
"RequestsGetTool",
"RequestsPatchTool",
"RequestsPostTool",
"RequestsPutTool",
"SceneXplainTool",
"SearchAPIResults",
"SearchAPIRun",
"SearxSearchResults",
"SearxSearchRun",
"ShellTool",
"SlackGetChannel",
"SlackGetMessage",
"SlackScheduleMessage",
"SlackSendMessage",
"SleepTool",
"StackExchangeTool",
"StdInInquireTool",
"SteamWebAPIQueryRun",
"SteamshipImageGenerationTool",
"TavilyAnswer",
"TavilySearchResults",
"VectorStoreQATool",
"VectorStoreQAWithSourcesTool",
"WikipediaQueryRun",
"WolframAlphaQueryRun",
"WriteFileTool",
"YahooFinanceNewsTool",
"YouSearchTool",
"YouTubeSearchTool",
"ZapierNLAListActions",
"ZapierNLARunAction",
"Detector",
"ZenGuardInput",
"ZenGuardTool",
"authenticate",
"format_tool_to_openai_function",
]
# Used for internal purposes
_DEPRECATED_TOOLS = {"PythonAstREPLTool", "PythonREPLTool"}
_module_lookup = {
"AINAppOps": "langchain_community.tools.ainetwork.app",
"AINOwnerOps": "langchain_community.tools.ainetwork.owner",
"AINRuleOps": "langchain_community.tools.ainetwork.rule",
"AINTransfer": "langchain_community.tools.ainetwork.transfer",
"AINValueOps": "langchain_community.tools.ainetwork.value",
"AIPluginTool": "langchain_community.tools.plugin",
"APIOperation": "langchain_community.tools.openapi.utils.api_models",
"ArxivQueryRun": "langchain_community.tools.arxiv.tool",
"AskNewsSearch": "langchain_community.tools.asknews.tool",
"AzureAiServicesDocumentIntelligenceTool": "langchain_community.tools.azure_ai_services", # noqa: E501
"AzureAiServicesImageAnalysisTool": "langchain_community.tools.azure_ai_services",
"AzureAiServicesSpeechToTextTool": "langchain_community.tools.azure_ai_services",
"AzureAiServicesTextToSpeechTool": "langchain_community.tools.azure_ai_services",
"AzureAiServicesTextAnalyticsForHealthTool": "langchain_community.tools.azure_ai_services", # noqa: E501
"AzureCogsFormRecognizerTool": "langchain_community.tools.azure_cognitive_services",
"AzureCogsImageAnalysisTool": "langchain_community.tools.azure_cognitive_services",
"AzureCogsSpeech2TextTool": "langchain_community.tools.azure_cognitive_services",
"AzureCogsText2SpeechTool": "langchain_community.tools.azure_cognitive_services",
"AzureCogsTextAnalyticsHealthTool": "langchain_community.tools.azure_cognitive_services", # noqa: E501
"BalanceSheets": "langchain_community.tools.financial_datasets.balance_sheets",
"BaseGraphQLTool": "langchain_community.tools.graphql.tool",
"BaseRequestsTool": "langchain_community.tools.requests.tool",
"BaseSQLDatabaseTool": "langchain_community.tools.sql_database.tool",
"BaseSparkSQLTool": "langchain_community.tools.spark_sql.tool",
"BaseTool": "langchain_core.tools",
"BearlyInterpreterTool": "langchain_community.tools.bearly.tool",
"BingSearchResults": "langchain_community.tools.bing_search.tool",
"BingSearchRun": "langchain_community.tools.bing_search.tool",
"BraveSearch": "langchain_community.tools.brave_search.tool",
"CashFlowStatements": "langchain_community.tools.financial_datasets.cash_flow_statements", # noqa: E501
"ClickTool": "langchain_community.tools.playwright",
"CogniswitchKnowledgeRequest": "langchain_community.tools.cogniswitch.tool",
"CogniswitchKnowledgeSourceFile": "langchain_community.tools.cogniswitch.tool",
"CogniswitchKnowledgeSourceURL": "langchain_community.tools.cogniswitch.tool",
"CogniswitchKnowledgeStatus": "langchain_community.tools.cogniswitch.tool",
"ConneryAction": "langchain_community.tools.connery",
"CopyFileTool": "langchain_community.tools.file_management",
"CurrentWebPageTool": "langchain_community.tools.playwright",
"DataheraldTextToSQL": "langchain_community.tools.dataherald.tool",
"DeleteFileTool": "langchain_community.tools.file_management",
"Detector": "langchain_community.tools.zenguard.tool",
"DuckDuckGoSearchResults": "langchain_community.tools.ddg_search.tool",
"DuckDuckGoSearchRun": "langchain_community.tools.ddg_search.tool",
"E2BDataAnalysisTool": "langchain_community.tools.e2b_data_analysis.tool",
"EdenAiExplicitImageTool": "langchain_community.tools.edenai",
"EdenAiObjectDetectionTool": "langchain_community.tools.edenai",
"EdenAiParsingIDTool": "langchain_community.tools.edenai",
"EdenAiParsingInvoiceTool": "langchain_community.tools.edenai",
"EdenAiSpeechToTextTool": "langchain_community.tools.edenai",
"EdenAiTextModerationTool": "langchain_community.tools.edenai",
"EdenAiTextToSpeechTool": "langchain_community.tools.edenai",
"EdenaiTool": "langchain_community.tools.edenai",
"ElevenLabsText2SpeechTool": "langchain_community.tools.eleven_labs.text2speech",
"ExtractHyperlinksTool": "langchain_community.tools.playwright",
"ExtractTextTool": "langchain_community.tools.playwright",
"FileSearchTool": "langchain_community.tools.file_management",
"GetElementsTool": "langchain_community.tools.playwright",
"GmailCreateDraft": "langchain_community.tools.gmail",
"GmailGetMessage": "langchain_community.tools.gmail",
"GmailGetThread": "langchain_community.tools.gmail",
"GmailSearch": "langchain_community.tools.gmail",
"GmailSendMessage": "langchain_community.tools.gmail",
"GoogleBooksQueryRun": "langchain_community.tools.google_books",
"GoogleCloudTextToSpeechTool": "langchain_community.tools.google_cloud.texttospeech", # noqa: E501
"GooglePlacesTool": "langchain_community.tools.google_places.tool",
"GoogleSearchResults": "langchain_community.tools.google_search.tool",
"GoogleSearchRun": "langchain_community.tools.google_search.tool",
"GoogleSerperResults": "langchain_community.tools.google_serper.tool",
"GoogleSerperRun": "langchain_community.tools.google_serper.tool",
"HumanInputRun": "langchain_community.tools.human.tool",
"IFTTTWebhook": "langchain_community.tools.ifttt",
"IncomeStatements": "langchain_community.tools.financial_datasets.income_statements", # noqa: E501
"InfoPowerBITool": "langchain_community.tools.powerbi.tool",
"InfoSQLDatabaseTool": "langchain_community.tools.sql_database.tool",
"InfoSparkSQLTool": "langchain_community.tools.spark_sql.tool",
"JiraAction": "langchain_community.tools.jira.tool",
"JinaSearch": "langchain_community.tools.jina_search.tool",
"JsonGetValueTool": "langchain_community.tools.json.tool",
"JsonListKeysTool": "langchain_community.tools.json.tool",
"ListDirectoryTool": "langchain_community.tools.file_management",
"ListPowerBITool": "langchain_community.tools.powerbi.tool",
"ListSQLDatabaseTool": "langchain_community.tools.sql_database.tool",
"ListSparkSQLTool": "langchain_community.tools.spark_sql.tool",
"MerriamWebsterQueryRun": "langchain_community.tools.merriam_webster.tool",
"MetaphorSearchResults": "langchain_community.tools.metaphor_search",
"MojeekSearch": "langchain_community.tools.mojeek_search.tool",
"MoveFileTool": "langchain_community.tools.file_management",
"NasaAction": "langchain_community.tools.nasa.tool",
"NavigateBackTool": "langchain_community.tools.playwright",
"NavigateTool": "langchain_community.tools.playwright",
"O365CreateDraftMessage": "langchain_community.tools.office365.create_draft_message", # noqa: E501
"O365SearchEmails": "langchain_community.tools.office365.messages_search",
"O365SearchEvents": "langchain_community.tools.office365.events_search",
"O365SendEvent": "langchain_community.tools.office365.send_event",
"O365SendMessage": "langchain_community.tools.office365.send_message",
"OpenAPISpec": "langchain_community.tools.openapi.utils.openapi_utils",
"OpenWeatherMapQueryRun": "langchain_community.tools.openweathermap.tool",
"PolygonAggregates": "langchain_community.tools.polygon.aggregates",
"PolygonFinancials": "langchain_community.tools.polygon.financials",
"PolygonLastQuote": "langchain_community.tools.polygon.last_quote",
"PolygonTickerNews": "langchain_community.tools.polygon.ticker_news",
"PubmedQueryRun": "langchain_community.tools.pubmed.tool",
"QueryCheckerTool": "langchain_community.tools.spark_sql.tool",
"QueryPowerBITool": "langchain_community.tools.powerbi.tool",
"QuerySQLCheckerTool": "langchain_community.tools.sql_database.tool",
"QuerySQLDatabaseTool": "langchain_community.tools.sql_database.tool",
# Legacy, kept for backwards compatibility.
"QuerySQLDataBaseTool": "langchain_community.tools.sql_database.tool",
"QuerySparkSQLTool": "langchain_community.tools.spark_sql.tool",
"ReadFileTool": "langchain_community.tools.file_management",
"RedditSearchRun": "langchain_community.tools.reddit_search.tool",
"RedditSearchSchema": "langchain_community.tools.reddit_search.tool",
"RequestsDeleteTool": "langchain_community.tools.requests.tool",
"RequestsGetTool": "langchain_community.tools.requests.tool",
"RequestsPatchTool": "langchain_community.tools.requests.tool",
"RequestsPostTool": "langchain_community.tools.requests.tool",
"RequestsPutTool": "langchain_community.tools.requests.tool",
"SceneXplainTool": "langchain_community.tools.scenexplain.tool",
"SearchAPIResults": "langchain_community.tools.searchapi.tool",
"SearchAPIRun": "langchain_community.tools.searchapi.tool",
"SearxSearchResults": "langchain_community.tools.searx_search.tool",
"SearxSearchRun": "langchain_community.tools.searx_search.tool",
"ShellTool": "langchain_community.tools.shell.tool",
"SlackGetChannel": "langchain_community.tools.slack.get_channel",
"SlackGetMessage": "langchain_community.tools.slack.get_message",
"SlackScheduleMessage": "langchain_community.tools.slack.schedule_message",
"SlackSendMessage": "langchain_community.tools.slack.send_message",
"SleepTool": "langchain_community.tools.sleep.tool",
"StackExchangeTool": "langchain_community.tools.stackexchange.tool",
"StdInInquireTool": "langchain_community.tools.interaction.tool",
"SteamWebAPIQueryRun": "langchain_community.tools.steam.tool",
"SteamshipImageGenerationTool": "langchain_community.tools.steamship_image_generation", # noqa: E501
"StructuredTool": "langchain_core.tools",
"TavilyAnswer": "langchain_community.tools.tavily_search",
"TavilySearchResults": "langchain_community.tools.tavily_search",
"Tool": "langchain_core.tools",
"VectorStoreQATool": "langchain_community.tools.vectorstore.tool",
"VectorStoreQAWithSourcesTool": "langchain_community.tools.vectorstore.tool",
"WikipediaQueryRun": "langchain_community.tools.wikipedia.tool",
"WolframAlphaQueryRun": "langchain_community.tools.wolfram_alpha.tool",
"WriteFileTool": "langchain_community.tools.file_management",
"YahooFinanceNewsTool": "langchain_community.tools.yahoo_finance_news",
"YouSearchTool": "langchain_community.tools.you.tool",
"YouTubeSearchTool": "langchain_community.tools.youtube.search",
"ZapierNLAListActions": "langchain_community.tools.zapier.tool",
"ZapierNLARunAction": "langchain_community.tools.zapier.tool",
"ZenGuardInput": "langchain_community.tools.zenguard.tool",
"ZenGuardTool": "langchain_community.tools.zenguard.tool",
"authenticate": "langchain_community.tools.office365.utils",
"format_tool_to_openai_function": "langchain_community.tools.convert_to_openai",
"tool": "langchain_core.tools",
}
def __getattr__(name: str) -> Any:
if name in _module_lookup:
module = importlib.import_module(_module_lookup[name])
return getattr(module, name)
raise AttributeError(f"module {__name__} has no attribute {name}")

View File

@@ -0,0 +1,102 @@
import builtins
import json
from enum import Enum
from typing import List, Optional, Type, Union
from langchain_core.callbacks import AsyncCallbackManagerForToolRun
from pydantic import BaseModel, Field
from langchain_community.tools.ainetwork.base import AINBaseTool
class AppOperationType(str, Enum):
"""Type of app operation as enumerator."""
SET_ADMIN = "SET_ADMIN"
GET_CONFIG = "GET_CONFIG"
class AppSchema(BaseModel):
"""Schema for app operations."""
type: AppOperationType = Field(...)
appName: str = Field(..., description="Name of the application on the blockchain")
address: Optional[Union[str, List[str]]] = Field(
None,
description=(
"A single address or a list of addresses. Default: current session's "
"address"
),
)
class AINAppOps(AINBaseTool):
"""Tool for app operations."""
name: str = "AINappOps"
description: str = """
Create an app in the AINetwork Blockchain database by creating the /apps/<appName> path.
An address set as `admin` can grant `owner` rights to other addresses (refer to `AINownerOps` for more details).
Also, `admin` is initialized to have all `owner` permissions and `rule` allowed for that path.
## appName Rule
- [a-z_0-9]+
## address Rules
- 0x[0-9a-fA-F]{40}
- Defaults to the current session's address
- Multiple addresses can be specified if needed
## SET_ADMIN Example 1
- type: SET_ADMIN
- appName: ain_project
### Result:
1. Path /apps/ain_project created.
2. Current session's address registered as admin.
## SET_ADMIN Example 2
- type: SET_ADMIN
- appName: test_project
- address: [<address1>, <address2>]
### Result:
1. Path /apps/test_project created.
2. <address1> and <address2> registered as admin.
""" # noqa: E501
args_schema: Type[BaseModel] = AppSchema
async def _arun(
self,
type: AppOperationType,
appName: str,
address: Optional[Union[str, List[str]]] = None,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
from ain.types import ValueOnlyTransactionInput
from ain.utils import getTimestamp
try:
if type is AppOperationType.SET_ADMIN:
if address is None:
address = self.interface.wallet.defaultAccount.address
if isinstance(address, str):
address = [address]
res = await self.interface.db.ref(
f"/manage_app/{appName}/create/{getTimestamp()}"
).setValue(
transactionInput=ValueOnlyTransactionInput(
value={"admin": {address: True for address in address}}
)
)
elif type is AppOperationType.GET_CONFIG:
res = await self.interface.db.ref(
f"/manage_app/{appName}/config"
).getValue()
else:
raise ValueError(f"Unsupported 'type': {type}.")
return json.dumps(res, ensure_ascii=False)
except Exception as e:
return f"{builtins.type(e).__name__}: {str(e)}"

View File

@@ -0,0 +1,73 @@
from __future__ import annotations
import asyncio
import threading
from enum import Enum
from typing import TYPE_CHECKING, Any, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import Field
from langchain_community.tools.ainetwork.utils import authenticate
if TYPE_CHECKING:
from ain.ain import Ain
class OperationType(str, Enum):
"""Type of operation as enumerator."""
SET = "SET"
GET = "GET"
class AINBaseTool(BaseTool):
"""Base class for the AINetwork tools."""
interface: Ain = Field(default_factory=authenticate)
"""The interface object for the AINetwork Blockchain."""
def _run(
self,
*args: Any,
run_manager: Optional[CallbackManagerForToolRun] = None,
**kwargs: Any,
) -> str:
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
if loop.is_closed():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
if loop.is_running():
result_container = []
def thread_target() -> None:
nonlocal result_container
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
try:
result_container.append(
new_loop.run_until_complete(self._arun(*args, **kwargs))
)
except Exception as e:
result_container.append(e)
finally:
new_loop.close()
thread = threading.Thread(target=thread_target)
thread.start()
thread.join()
result = result_container[0]
if isinstance(result, Exception):
raise result
return result
else:
result = loop.run_until_complete(self._arun(*args, **kwargs))
loop.close()
return result

View File

@@ -0,0 +1,115 @@
import builtins
import json
from typing import List, Optional, Type, Union
from langchain_core.callbacks import AsyncCallbackManagerForToolRun
from pydantic import BaseModel, Field
from langchain_community.tools.ainetwork.base import AINBaseTool, OperationType
class RuleSchema(BaseModel):
"""Schema for owner operations."""
type: OperationType = Field(...)
path: str = Field(..., description="Blockchain reference path")
address: Optional[Union[str, List[str]]] = Field(
None, description="A single address or a list of addresses"
)
write_owner: Optional[bool] = Field(
False, description="Authority to edit the `owner` property of the path"
)
write_rule: Optional[bool] = Field(
False, description="Authority to edit `write rule` for the path"
)
write_function: Optional[bool] = Field(
False, description="Authority to `set function` for the path"
)
branch_owner: Optional[bool] = Field(
False, description="Authority to initialize `owner` of sub-paths"
)
class AINOwnerOps(AINBaseTool):
"""Tool for owner operations."""
name: str = "AINownerOps"
description: str = """
Rules for `owner` in AINetwork Blockchain database.
An address set as `owner` can modify permissions according to its granted authorities
## Path Rule
- (/[a-zA-Z_0-9]+)+
- Permission checks ascend from the most specific (child) path to broader (parent) paths until an `owner` is located.
## Address Rules
- 0x[0-9a-fA-F]{40}: 40-digit hexadecimal address
- *: All addresses permitted
- Defaults to the current session's address
## SET
- `SET` alters permissions for specific addresses, while other addresses remain unaffected.
- When removing an address of `owner`, set all authorities for that address to false.
- message `write_owner permission evaluated false` if fail
### Example
- type: SET
- path: /apps/langchain
- address: [<address 1>, <address 2>]
- write_owner: True
- write_rule: True
- write_function: True
- branch_owner: True
## GET
- Provides all addresses with `owner` permissions and their authorities in the path.
### Example
- type: GET
- path: /apps/langchain
""" # noqa: E501
args_schema: Type[BaseModel] = RuleSchema
async def _arun(
self,
type: OperationType,
path: str,
address: Optional[Union[str, List[str]]] = None,
write_owner: Optional[bool] = None,
write_rule: Optional[bool] = None,
write_function: Optional[bool] = None,
branch_owner: Optional[bool] = None,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
from ain.types import ValueOnlyTransactionInput
try:
if type is OperationType.SET:
if address is None:
address = self.interface.wallet.defaultAccount.address
if isinstance(address, str):
address = [address]
res = await self.interface.db.ref(path).setOwner(
transactionInput=ValueOnlyTransactionInput(
value={
".owner": {
"owners": {
address: {
"write_owner": write_owner or False,
"write_rule": write_rule or False,
"write_function": write_function or False,
"branch_owner": branch_owner or False,
}
for address in address
}
}
}
)
)
elif type is OperationType.GET:
res = await self.interface.db.ref(path).getOwner()
else:
raise ValueError(f"Unsupported 'type': {type}.")
return json.dumps(res, ensure_ascii=False)
except Exception as e:
return f"{builtins.type(e).__name__}: {str(e)}"

View File

@@ -0,0 +1,82 @@
import builtins
import json
from typing import Optional, Type
from langchain_core.callbacks import AsyncCallbackManagerForToolRun
from pydantic import BaseModel, Field
from langchain_community.tools.ainetwork.base import AINBaseTool, OperationType
class RuleSchema(BaseModel):
"""Schema for owner operations."""
type: OperationType = Field(...)
path: str = Field(..., description="Path on the blockchain where the rule applies")
eval: Optional[str] = Field(None, description="eval string to determine permission")
class AINRuleOps(AINBaseTool):
"""Tool for owner operations."""
name: str = "AINruleOps"
description: str = """
Covers the write `rule` for the AINetwork Blockchain database. The SET type specifies write permissions using the `eval` variable as a JavaScript eval string.
In order to AINvalueOps with SET at the path, the execution result of the `eval` string must be true.
## Path Rules
1. Allowed characters for directory: `[a-zA-Z_0-9]`
2. Use `$<key>` for template variables as directory.
## Eval String Special Variables
- auth.addr: Address of the writer for the path
- newData: New data for the path
- data: Current data for the path
- currentTime: Time in seconds
- lastBlockNumber: Latest processed block number
## Eval String Functions
- getValue(<path>)
- getRule(<path>)
- getOwner(<path>)
- getFunction(<path>)
- evalRule(<path>, <value to set>, auth, currentTime)
- evalOwner(<path>, 'write_owner', auth)
## SET Example
- type: SET
- path: /apps/langchain_project_1/$from/$to/$img
- eval: auth.addr===$from&&!getValue('/apps/image_db/'+$img)
## GET Example
- type: GET
- path: /apps/langchain_project_1
""" # noqa: E501
args_schema: Type[BaseModel] = RuleSchema
async def _arun(
self,
type: OperationType,
path: str,
eval: Optional[str] = None,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
from ain.types import ValueOnlyTransactionInput
try:
if type is OperationType.SET:
if eval is None:
raise ValueError("'eval' is required for SET operation.")
res = await self.interface.db.ref(path).setRule(
transactionInput=ValueOnlyTransactionInput(
value={".rule": {"write": eval}}
)
)
elif type is OperationType.GET:
res = await self.interface.db.ref(path).getRule()
else:
raise ValueError(f"Unsupported 'type': {type}.")
return json.dumps(res, ensure_ascii=False)
except Exception as e:
return f"{builtins.type(e).__name__}: {str(e)}"

View File

@@ -0,0 +1,34 @@
import json
from typing import Optional, Type
from langchain_core.callbacks import AsyncCallbackManagerForToolRun
from pydantic import BaseModel, Field
from langchain_community.tools.ainetwork.base import AINBaseTool
class TransferSchema(BaseModel):
"""Schema for transfer operations."""
address: str = Field(..., description="Address to transfer AIN to")
amount: int = Field(..., description="Amount of AIN to transfer")
class AINTransfer(AINBaseTool):
"""Tool for transfer operations."""
name: str = "AINtransfer"
description: str = "Transfers AIN to a specified address"
args_schema: Type[TransferSchema] = TransferSchema
async def _arun(
self,
address: str,
amount: int,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
try:
res = await self.interface.wallet.transfer(address, amount, nonce=-1)
return json.dumps(res, ensure_ascii=False)
except Exception as e:
return f"{type(e).__name__}: {str(e)}"

View File

@@ -0,0 +1,63 @@
"""AINetwork Blockchain tool utils."""
from __future__ import annotations
import os
from typing import TYPE_CHECKING, Literal, Optional
if TYPE_CHECKING:
from ain.ain import Ain
def authenticate(network: Optional[Literal["mainnet", "testnet"]] = "testnet") -> Ain:
"""Authenticate using the AIN Blockchain"""
try:
from ain.ain import Ain
except ImportError as e:
raise ImportError(
"Cannot import ain-py related modules. Please install the package with "
"`pip install ain-py`."
) from e
if network == "mainnet":
provider_url = "https://mainnet-api.ainetwork.ai/"
chain_id = 1
if "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ:
private_key = os.environ["AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY"]
else:
raise EnvironmentError(
"Error: The AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY environmental variable "
"has not been set."
)
elif network == "testnet":
provider_url = "https://testnet-api.ainetwork.ai/"
chain_id = 0
if "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ:
private_key = os.environ["AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY"]
else:
raise EnvironmentError(
"Error: The AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY environmental variable "
"has not been set."
)
elif network is None:
if (
"AIN_BLOCKCHAIN_PROVIDER_URL" in os.environ
and "AIN_BLOCKCHAIN_CHAIN_ID" in os.environ
and "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ
):
provider_url = os.environ["AIN_BLOCKCHAIN_PROVIDER_URL"]
chain_id = int(os.environ["AIN_BLOCKCHAIN_CHAIN_ID"])
private_key = os.environ["AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY"]
else:
raise EnvironmentError(
"Error: The AIN_BLOCKCHAIN_PROVIDER_URL and "
"AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY and AIN_BLOCKCHAIN_CHAIN_ID "
"environmental variable has not been set."
)
else:
raise ValueError(f"Unsupported 'network': {network}")
ain = Ain(provider_url, chain_id)
ain.wallet.addAndSetDefaultAccount(private_key)
return ain

View File

@@ -0,0 +1,85 @@
import builtins
import json
from typing import Optional, Type, Union
from langchain_core.callbacks import AsyncCallbackManagerForToolRun
from pydantic import BaseModel, Field
from langchain_community.tools.ainetwork.base import AINBaseTool, OperationType
class ValueSchema(BaseModel):
"""Schema for value operations."""
type: OperationType = Field(...)
path: str = Field(..., description="Blockchain reference path")
value: Optional[Union[int, str, float, dict]] = Field(
None, description="Value to be set at the path"
)
class AINValueOps(AINBaseTool):
"""Tool for value operations."""
name: str = "AINvalueOps"
description: str = """
Covers the read and write value for the AINetwork Blockchain database.
## SET
- Set a value at a given path
### Example
- type: SET
- path: /apps/langchain_test_1/object
- value: {1: 2, "34": 56}
## GET
- Retrieve a value at a given path
### Example
- type: GET
- path: /apps/langchain_test_1/DB
## Special paths
- `/accounts/<address>/balance`: Account balance
- `/accounts/<address>/nonce`: Account nonce
- `/apps`: Applications
- `/consensus`: Consensus
- `/checkin`: Check-in
- `/deposit/<service id>/<address>/<deposit id>`: Deposit
- `/deposit_accounts/<service id>/<address>/<account id>`: Deposit accounts
- `/escrow`: Escrow
- `/payments`: Payment
- `/sharding`: Sharding
- `/token/name`: Token name
- `/token/symbol`: Token symbol
- `/token/total_supply`: Token total supply
- `/transfer/<address from>/<address to>/<key>/value`: Transfer
- `/withdraw/<service id>/<address>/<withdraw id>`: Withdraw
"""
args_schema: Type[BaseModel] = ValueSchema
async def _arun(
self,
type: OperationType,
path: str,
value: Optional[Union[int, str, float, dict]] = None,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
from ain.types import ValueOnlyTransactionInput
try:
if type is OperationType.SET:
if value is None:
raise ValueError("'value' is required for SET operation.")
res = await self.interface.db.ref(path).setValue(
transactionInput=ValueOnlyTransactionInput(value=value)
)
elif type is OperationType.GET:
res = await self.interface.db.ref(path).getValue()
else:
raise ValueError(f"Unsupported 'type': {type}.")
return json.dumps(res, ensure_ascii=False)
except Exception as e:
return f"{builtins.type(e).__name__}: {str(e)}"

View File

@@ -0,0 +1,9 @@
"""Amadeus tools."""
from langchain_community.tools.amadeus.closest_airport import AmadeusClosestAirport
from langchain_community.tools.amadeus.flight_search import AmadeusFlightSearch
__all__ = [
"AmadeusClosestAirport",
"AmadeusFlightSearch",
]

View File

@@ -0,0 +1,19 @@
"""Base class for Amadeus tools."""
from __future__ import annotations
from typing import TYPE_CHECKING
from langchain_core.tools import BaseTool
from pydantic import Field
from langchain_community.tools.amadeus.utils import authenticate
if TYPE_CHECKING:
from amadeus import Client
class AmadeusBaseTool(BaseTool):
"""Base Tool for Amadeus."""
client: Client = Field(default_factory=authenticate)

View File

@@ -0,0 +1,62 @@
from typing import Any, Dict, Optional, Type
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.language_models import BaseLanguageModel
from pydantic import BaseModel, Field, model_validator
from langchain_community.chat_models import ChatOpenAI
from langchain_community.tools.amadeus.base import AmadeusBaseTool
class ClosestAirportSchema(BaseModel):
"""Schema for the AmadeusClosestAirport tool."""
location: str = Field(
description=(
" The location for which you would like to find the nearest airport "
" along with optional details such as country, state, region, or "
" province, allowing for easy processing and identification of "
" the closest airport. Examples of the format are the following:\n"
" Cali, Colombia\n "
" Lincoln, Nebraska, United States\n"
" New York, United States\n"
" Sydney, New South Wales, Australia\n"
" Rome, Lazio, Italy\n"
" Toronto, Ontario, Canada\n"
)
)
class AmadeusClosestAirport(AmadeusBaseTool):
"""Tool for finding the closest airport to a particular location."""
name: str = "closest_airport"
description: str = (
"Use this tool to find the closest airport to a particular location."
)
args_schema: Type[ClosestAirportSchema] = ClosestAirportSchema
llm: Optional[BaseLanguageModel] = Field(default=None)
"""Tool's llm used for calculating the closest airport. Defaults to `ChatOpenAI`."""
@model_validator(mode="before")
@classmethod
def set_llm(cls, values: Dict[str, Any]) -> Any:
if not values.get("llm"):
# For backward-compatibility
values["llm"] = ChatOpenAI(temperature=0)
return values
def _run(
self,
location: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
content = (
f" What is the nearest airport to {location}? Please respond with the "
" airport's International Air Transport Association (IATA) Location "
' Identifier in the following JSON format. JSON: "iataCode": "IATA '
' Location Identifier" '
)
return self.llm.invoke(content) # type: ignore[union-attr]

View File

@@ -0,0 +1,153 @@
import logging
from datetime import datetime as dt
from typing import Dict, Optional, Type
from langchain_core.callbacks import CallbackManagerForToolRun
from pydantic import BaseModel, Field
from langchain_community.tools.amadeus.base import AmadeusBaseTool
logger = logging.getLogger(__name__)
class FlightSearchSchema(BaseModel):
"""Schema for the AmadeusFlightSearch tool."""
originLocationCode: str = Field(
description=(
" The three letter International Air Transport "
" Association (IATA) Location Identifier for the "
" search's origin airport. "
)
)
destinationLocationCode: str = Field(
description=(
" The three letter International Air Transport "
" Association (IATA) Location Identifier for the "
" search's destination airport. "
)
)
departureDateTimeEarliest: str = Field(
description=(
" The earliest departure datetime from the origin airport "
" for the flight search in the following format: "
' "YYYY-MM-DDTHH:MM:SS", where "T" separates the date and time '
' components. For example: "2023-06-09T10:30:00" represents '
" June 9th, 2023, at 10:30 AM. "
)
)
departureDateTimeLatest: str = Field(
description=(
" The latest departure datetime from the origin airport "
" for the flight search in the following format: "
' "YYYY-MM-DDTHH:MM:SS", where "T" separates the date and time '
' components. For example: "2023-06-09T10:30:00" represents '
" June 9th, 2023, at 10:30 AM. "
)
)
page_number: int = Field(
default=1,
description="The specific page number of flight results to retrieve",
)
class AmadeusFlightSearch(AmadeusBaseTool):
"""Tool for searching for a single flight between two airports."""
name: str = "single_flight_search"
description: str = (
" Use this tool to search for a single flight between the origin and "
" destination airports at a departure between an earliest and "
" latest datetime. "
)
args_schema: Type[FlightSearchSchema] = FlightSearchSchema
def _run(
self,
originLocationCode: str,
destinationLocationCode: str,
departureDateTimeEarliest: str,
departureDateTimeLatest: str,
page_number: int = 1,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> list:
try:
from amadeus import ResponseError
except ImportError as e:
raise ImportError(
"Unable to import amadeus, please install with `pip install amadeus`."
) from e
RESULTS_PER_PAGE = 10
# Authenticate and retrieve a client
client = self.client
# Check that earliest and latest dates are in the same day
earliestDeparture = dt.strptime(departureDateTimeEarliest, "%Y-%m-%dT%H:%M:%S")
latestDeparture = dt.strptime(departureDateTimeLatest, "%Y-%m-%dT%H:%M:%S")
if earliestDeparture.date() != latestDeparture.date():
logger.error(
" Error: Earliest and latest departure dates need to be the "
" same date. If you're trying to search for round-trip "
" flights, call this function for the outbound flight first, "
" and then call again for the return flight. "
)
return [None]
# Collect all results from the Amadeus Flight Offers Search API
response = None
try:
response = client.shopping.flight_offers_search.get(
originLocationCode=originLocationCode,
destinationLocationCode=destinationLocationCode,
departureDate=latestDeparture.strftime("%Y-%m-%d"),
adults=1,
)
except ResponseError as error:
print(error) # noqa: T201
# Generate output dictionary
output = []
if response is not None:
for offer in response.data:
itinerary: Dict = {}
itinerary["price"] = {}
itinerary["price"]["total"] = offer["price"]["total"]
currency = offer["price"]["currency"]
currency = response.result["dictionaries"]["currencies"][currency]
itinerary["price"]["currency"] = {}
itinerary["price"]["currency"] = currency
segments = []
for segment in offer["itineraries"][0]["segments"]:
flight = {}
flight["departure"] = segment["departure"]
flight["arrival"] = segment["arrival"]
flight["flightNumber"] = segment["number"]
carrier = segment["carrierCode"]
carrier = response.result["dictionaries"]["carriers"][carrier]
flight["carrier"] = carrier
segments.append(flight)
itinerary["segments"] = []
itinerary["segments"] = segments
output.append(itinerary)
# Filter out flights after latest departure time
for index, offer in enumerate(output):
offerDeparture = dt.strptime(
offer["segments"][0]["departure"]["at"], "%Y-%m-%dT%H:%M:%S"
)
if offerDeparture > latestDeparture:
output.pop(index)
# Return the paginated results
startIndex = (page_number - 1) * RESULTS_PER_PAGE
endIndex = startIndex + RESULTS_PER_PAGE
return output[startIndex:endIndex]

View File

@@ -0,0 +1,43 @@
"""O365 tool utils."""
from __future__ import annotations
import logging
import os
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from amadeus import Client
logger = logging.getLogger(__name__)
def authenticate() -> Client:
"""Authenticate using the Amadeus API"""
try:
from amadeus import Client
except ImportError as e:
raise ImportError(
"Cannot import amadeus. Please install the package with "
"`pip install amadeus`."
) from e
if "AMADEUS_CLIENT_ID" in os.environ and "AMADEUS_CLIENT_SECRET" in os.environ:
client_id = os.environ["AMADEUS_CLIENT_ID"]
client_secret = os.environ["AMADEUS_CLIENT_SECRET"]
else:
logger.error(
"Error: The AMADEUS_CLIENT_ID and AMADEUS_CLIENT_SECRET environmental "
"variables have not been set. Visit the following link on how to "
"acquire these authorization tokens: "
"https://developers.amadeus.com/register"
)
return None
hostname = "test" # Default hostname
if "AMADEUS_HOSTNAME" in os.environ:
hostname = os.environ["AMADEUS_HOSTNAME"]
client = Client(client_id=client_id, client_secret=client_secret, hostname=hostname)
return client

View File

@@ -0,0 +1,6 @@
from langchain_community.tools.arxiv.tool import ArxivQueryRun
"""Arxiv API toolkit."""
"""Tool for the Arxiv Search API."""
__all__ = ["ArxivQueryRun"]

View File

@@ -0,0 +1,39 @@
"""Tool for the Arxiv API."""
from typing import Optional, Type
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from langchain_community.utilities.arxiv import ArxivAPIWrapper
class ArxivInput(BaseModel):
"""Input for the Arxiv tool."""
query: str = Field(description="search query to look up")
class ArxivQueryRun(BaseTool):
"""Tool that searches the Arxiv API."""
name: str = "arxiv"
description: str = (
"A wrapper around Arxiv.org "
"Useful for when you need to answer questions about Physics, Mathematics, "
"Computer Science, Quantitative Biology, Quantitative Finance, Statistics, "
"Electrical Engineering, and Economics "
"from scientific articles on arxiv.org. "
"Input should be a search query."
)
api_wrapper: ArxivAPIWrapper = Field(default_factory=ArxivAPIWrapper) # type: ignore[arg-type]
args_schema: Type[BaseModel] = ArxivInput
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the Arxiv tool."""
return self.api_wrapper.run(query)

View File

@@ -0,0 +1,7 @@
"""AskNews API toolkit."""
from langchain_community.tools.asknews.tool import (
AskNewsSearch,
)
__all__ = ["AskNewsSearch"]

View File

@@ -0,0 +1,82 @@
"""
Tool for the AskNews API.
To use this tool, you must first set your credentials as environment variables:
ASKNEWS_CLIENT_ID
ASKNEWS_CLIENT_SECRET
"""
from typing import Any, Optional, Type
from langchain_core.callbacks import (
AsyncCallbackManagerForToolRun,
CallbackManagerForToolRun,
)
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from langchain_community.utilities.asknews import AskNewsAPIWrapper
class SearchInput(BaseModel):
"""Input for the AskNews Search tool."""
query: str = Field(
description="Search query to be used for finding real-time or historical news "
"information."
)
hours_back: Optional[int] = Field(
0,
description="If the Assistant deems that the event may have occurred more "
"than 48 hours ago, it estimates the number of hours back to search. For "
"example, if the event was one month ago, the Assistant may set this to 720. "
"One week would be 168. The Assistant can estimate up to on year back (8760).",
)
class AskNewsSearch(BaseTool):
"""Tool that searches the AskNews API."""
name: str = "asknews_search"
description: str = (
"This tool allows you to perform a search on up-to-date news and historical "
"news. If you needs news from more than 48 hours ago, you can estimate the "
"number of hours back to search."
)
api_wrapper: AskNewsAPIWrapper = Field(default_factory=AskNewsAPIWrapper)
max_results: int = 10
args_schema: Optional[Type[BaseModel]] = SearchInput
def _run(
self,
query: str,
hours_back: int = 0,
run_manager: Optional[CallbackManagerForToolRun] = None,
**kwargs: Any,
) -> str:
"""Use the tool."""
try:
return self.api_wrapper.search_news(
query,
hours_back=hours_back,
max_results=self.max_results,
)
except Exception as e:
return repr(e)
async def _arun(
self,
query: str,
hours_back: int = 0,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
**kwargs: Any,
) -> str:
"""Use the tool asynchronously."""
try:
return await self.api_wrapper.asearch_news(
query,
hours_back=hours_back,
max_results=self.max_results,
)
except Exception as e:
return repr(e)

View File

@@ -0,0 +1,7 @@
from langchain_community.tools.audio.huggingface_text_to_speech_inference import (
HuggingFaceTextToSpeechModelInference,
)
__all__ = [
"HuggingFaceTextToSpeechModelInference",
]

View File

@@ -0,0 +1,127 @@
import logging
import os
import uuid
from datetime import datetime
from typing import Callable, Literal, Optional
import requests
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import SecretStr
logger = logging.getLogger(__name__)
class HuggingFaceTextToSpeechModelInference(BaseTool):
"""HuggingFace Text-to-Speech Model Inference.
Requirements:
- Environment variable ``HUGGINGFACE_API_KEY`` must be set,
or passed as a named parameter to the constructor.
"""
name: str = "openai_text_to_speech"
"""Name of the tool."""
description: str = "A wrapper around OpenAI Text-to-Speech API. "
"""Description of the tool."""
model: str
"""Model name."""
file_extension: str
"""File extension of the output audio file."""
destination_dir: str
"""Directory to save the output audio file."""
file_namer: Callable[[], str]
"""Function to generate unique file names."""
api_url: str
huggingface_api_key: SecretStr
_HUGGINGFACE_API_KEY_ENV_NAME: str = "HUGGINGFACE_API_KEY"
_HUGGINGFACE_API_URL_ROOT: str = "https://api-inference.huggingface.co/models"
def __init__(
self,
model: str,
file_extension: str,
*,
destination_dir: str = "./tts",
file_naming_func: Literal["uuid", "timestamp"] = "uuid",
huggingface_api_key: Optional[SecretStr] = None,
_HUGGINGFACE_API_KEY_ENV_NAME: str = "HUGGINGFACE_API_KEY",
_HUGGINGFACE_API_URL_ROOT: str = "https://api-inference.huggingface.co/models",
) -> None:
if not huggingface_api_key:
huggingface_api_key = SecretStr(
os.getenv(_HUGGINGFACE_API_KEY_ENV_NAME, "")
)
if (
not huggingface_api_key
or not huggingface_api_key.get_secret_value()
or huggingface_api_key.get_secret_value() == ""
):
raise ValueError(
f"'{_HUGGINGFACE_API_KEY_ENV_NAME}' must be or set or passed"
)
# Sanitize file extension to prevent path traversal attacks
file_extension = os.path.basename(file_extension).lstrip(".")
if not file_extension or "/" in file_extension or "\\" in file_extension:
raise ValueError("Invalid file extension")
if file_naming_func == "uuid":
file_namer = lambda: str(uuid.uuid4()) # noqa: E731
elif file_naming_func == "timestamp":
file_namer = lambda: str(int(datetime.now().timestamp())) # noqa: E731
else:
raise ValueError(
f"Invalid value for 'file_naming_func': {file_naming_func}"
)
super().__init__(
model=model,
file_extension=file_extension,
api_url=f"{_HUGGINGFACE_API_URL_ROOT}/{model}",
destination_dir=destination_dir,
file_namer=file_namer,
huggingface_api_key=huggingface_api_key,
_HUGGINGFACE_API_KEY_ENV_NAME=_HUGGINGFACE_API_KEY_ENV_NAME,
_HUGGINGFACE_API_URL_ROOT=_HUGGINGFACE_API_URL_ROOT,
)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
response = requests.post(
self.api_url,
headers={
"Authorization": f"Bearer {self.huggingface_api_key.get_secret_value()}"
},
json={"inputs": query},
)
audio_bytes = response.content
try:
os.makedirs(self.destination_dir, exist_ok=True)
except Exception as e:
logger.error(f"Error creating directory '{self.destination_dir}': {e}")
raise
output_file = os.path.join(
self.destination_dir,
f"{str(self.file_namer())}.{self.file_extension}",
)
try:
with open(output_file, mode="xb") as f:
f.write(audio_bytes)
except FileExistsError:
raise ValueError("Output name must be unique")
except Exception as e:
logger.error(f"Error occurred while creating file: {e}")
raise
return output_file

View File

@@ -0,0 +1,25 @@
"""Azure AI Services Tools."""
from langchain_community.tools.azure_ai_services.document_intelligence import (
AzureAiServicesDocumentIntelligenceTool,
)
from langchain_community.tools.azure_ai_services.image_analysis import (
AzureAiServicesImageAnalysisTool,
)
from langchain_community.tools.azure_ai_services.speech_to_text import (
AzureAiServicesSpeechToTextTool,
)
from langchain_community.tools.azure_ai_services.text_analytics_for_health import (
AzureAiServicesTextAnalyticsForHealthTool,
)
from langchain_community.tools.azure_ai_services.text_to_speech import (
AzureAiServicesTextToSpeechTool,
)
__all__ = [
"AzureAiServicesDocumentIntelligenceTool",
"AzureAiServicesImageAnalysisTool",
"AzureAiServicesSpeechToTextTool",
"AzureAiServicesTextToSpeechTool",
"AzureAiServicesTextAnalyticsForHealthTool",
]

View File

@@ -0,0 +1,146 @@
from __future__ import annotations
import logging
from typing import Any, Dict, List, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
from langchain_community.tools.azure_ai_services.utils import (
detect_file_src_type,
)
logger = logging.getLogger(__name__)
class AzureAiServicesDocumentIntelligenceTool(BaseTool):
"""Tool that queries the Azure AI Services Document Intelligence API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/quickstarts/get-started-sdks-rest-api?view=doc-intel-4.0.0&pivots=programming-language-python
"""
azure_ai_services_key: str = "" #: :meta private:
azure_ai_services_endpoint: str = "" #: :meta private:
doc_analysis_client: Any #: :meta private:
name: str = "azure_ai_services_document_intelligence"
description: str = (
"A wrapper around Azure AI Services Document Intelligence. "
"Useful for when you need to "
"extract text, tables, and key-value pairs from documents. "
"Input should be a url to a document."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_ai_services_key = get_from_dict_or_env(
values, "azure_ai_services_key", "AZURE_AI_SERVICES_KEY"
)
azure_ai_services_endpoint = get_from_dict_or_env(
values, "azure_ai_services_endpoint", "AZURE_AI_SERVICES_ENDPOINT"
)
try:
from azure.ai.formrecognizer import DocumentAnalysisClient
from azure.core.credentials import AzureKeyCredential
values["doc_analysis_client"] = DocumentAnalysisClient(
endpoint=azure_ai_services_endpoint,
credential=AzureKeyCredential(azure_ai_services_key),
)
except ImportError:
raise ImportError(
"azure-ai-formrecognizer is not installed. "
"Run `pip install azure-ai-formrecognizer` to install."
)
return values
def _parse_tables(self, tables: List[Any]) -> List[Any]:
result = []
for table in tables:
rc, cc = table.row_count, table.column_count
_table = [["" for _ in range(cc)] for _ in range(rc)]
for cell in table.cells:
_table[cell.row_index][cell.column_index] = cell.content
result.append(_table)
return result
def _parse_kv_pairs(self, kv_pairs: List[Any]) -> List[Any]:
result = []
for kv_pair in kv_pairs:
key = kv_pair.key.content if kv_pair.key else ""
value = kv_pair.value.content if kv_pair.value else ""
result.append((key, value))
return result
def _document_analysis(self, document_path: str) -> Dict:
document_src_type = detect_file_src_type(document_path)
if document_src_type == "local":
with open(document_path, "rb") as document:
poller = self.doc_analysis_client.begin_analyze_document(
"prebuilt-document", document
)
elif document_src_type == "remote":
poller = self.doc_analysis_client.begin_analyze_document_from_url(
"prebuilt-document", document_path
)
else:
raise ValueError(f"Invalid document path: {document_path}")
result = poller.result()
res_dict = {}
if result.content is not None:
res_dict["content"] = result.content
if result.tables is not None:
res_dict["tables"] = self._parse_tables(result.tables)
if result.key_value_pairs is not None:
res_dict["key_value_pairs"] = self._parse_kv_pairs(result.key_value_pairs)
return res_dict
def _format_document_analysis_result(self, document_analysis_result: Dict) -> str:
formatted_result = []
if "content" in document_analysis_result:
formatted_result.append(
f"Content: {document_analysis_result['content']}".replace("\n", " ")
)
if "tables" in document_analysis_result:
for i, table in enumerate(document_analysis_result["tables"]):
formatted_result.append(f"Table {i}: {table}".replace("\n", " "))
if "key_value_pairs" in document_analysis_result:
for kv_pair in document_analysis_result["key_value_pairs"]:
formatted_result.append(
f"{kv_pair[0]}: {kv_pair[1]}".replace("\n", " ")
)
return "\n".join(formatted_result)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
document_analysis_result = self._document_analysis(query)
if not document_analysis_result:
return "No good document analysis result was found"
return self._format_document_analysis_result(document_analysis_result)
except Exception as e:
raise RuntimeError(
f"Error while running AzureAiServicesDocumentIntelligenceTool: {e}"
)

View File

@@ -0,0 +1,195 @@
from __future__ import annotations
import logging
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
from langchain_community.tools.azure_ai_services.utils import (
detect_file_src_type,
)
logger = logging.getLogger(__name__)
class AzureAiServicesImageAnalysisTool(BaseTool):
"""Tool that queries the Azure AI Services Image Analysis API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/azure/ai-services/computer-vision/quickstarts-sdk/image-analysis-client-library-40
Attributes:
azure_ai_services_key (Optional[str]): The API key for Azure AI Services.
azure_ai_services_endpoint (Optional[str]): The endpoint URL for Azure AI Services.
visual_features Any: The visual features to analyze in the image, can be set as
either strings or azure.ai.vision.imageanalysis.models.VisualFeatures.
(e.g. 'TAGS', VisualFeatures.CAPTION).
image_analysis_client (Any): The client for interacting
with Azure AI Services Image Analysis.
name (str): The name of the tool.
description (str): A description of the tool,
including its purpose and expected input.
"""
azure_ai_services_key: Optional[str] = None #: :meta private:
azure_ai_services_endpoint: Optional[str] = None #: :meta private:
visual_features: Any = None
image_analysis_client: Any = None #: :meta private:
name: str = "azure_ai_services_image_analysis"
description: str = (
"A wrapper around Azure AI Services Image Analysis. "
"Useful for when you need to analyze images. "
"Input must be a url string or path string to an image."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_ai_services_key = get_from_dict_or_env(
values, "azure_ai_services_key", "AZURE_AI_SERVICES_KEY"
)
azure_ai_services_endpoint = get_from_dict_or_env(
values, "azure_ai_services_endpoint", "AZURE_AI_SERVICES_ENDPOINT"
)
"""Validate that azure-ai-vision-imageanalysis is installed."""
try:
from azure.ai.vision.imageanalysis import ImageAnalysisClient
from azure.ai.vision.imageanalysis.models import VisualFeatures
from azure.core.credentials import AzureKeyCredential
except ImportError:
raise ImportError(
"azure-ai-vision-imageanalysis is not installed. "
"Run `pip install azure-ai-vision-imageanalysis` to install. "
)
"""Validate Azure AI Vision Image Analysis client can be initialized."""
try:
values["image_analysis_client"] = ImageAnalysisClient(
endpoint=azure_ai_services_endpoint,
credential=AzureKeyCredential(azure_ai_services_key),
)
except Exception as e:
raise RuntimeError(
f"Initialization of Azure AI Vision Image Analysis client failed: {e}"
)
visual_features = values.get(
"visual_features",
[
VisualFeatures.TAGS,
VisualFeatures.OBJECTS,
VisualFeatures.CAPTION,
VisualFeatures.READ,
],
)
values["visual_features"] = visual_features
return values
def _image_analysis(self, image_path: str) -> Dict:
try:
from azure.ai.vision.imageanalysis import ImageAnalysisClient
except ImportError:
pass
self.image_analysis_client: ImageAnalysisClient
image_src_type = detect_file_src_type(image_path)
if image_src_type == "local":
with open(image_path, "rb") as image_file:
image_data = image_file.read()
result = self.image_analysis_client.analyze(
image_data=image_data,
visual_features=self.visual_features,
)
elif image_src_type == "remote":
result = self.image_analysis_client.analyze_from_url(
image_url=image_path,
visual_features=self.visual_features,
)
else:
raise ValueError(f"Invalid image path: {image_path}")
res_dict = {}
if result:
if result.caption is not None:
res_dict["caption"] = result.caption.text
if result.objects is not None:
res_dict["objects"] = [obj.tags[0].name for obj in result.objects.list]
if result.tags is not None:
res_dict["tags"] = [tag.name for tag in result.tags.list]
if result.read is not None and len(result.read.blocks) > 0:
res_dict["text"] = [line.text for line in result.read.blocks[0].lines]
if result.dense_captions is not None and len(result.dense_captions) > 0:
res_dict["dense_captions"] = [
str(dc) for dc in result.dense_captions.list
]
if result.smart_crops is not None and len(result.smart_crops) > 0:
res_dict["smart_crops"] = [str(sc) for sc in result.smart_crops.list]
if result.people is not None and len(result.people) > 0:
res_dict["people"] = [str(p) for p in result.people.list]
return res_dict
def _format_image_analysis_result(self, image_analysis_result: Dict) -> str:
formatted_result = []
if "caption" in image_analysis_result:
formatted_result.append("Caption: " + image_analysis_result["caption"])
if (
"objects" in image_analysis_result
and len(image_analysis_result["objects"]) > 0
):
formatted_result.append(
"Objects: " + ", ".join(image_analysis_result["objects"])
)
if "tags" in image_analysis_result and len(image_analysis_result["tags"]) > 0:
formatted_result.append("Tags: " + ", ".join(image_analysis_result["tags"]))
if "text" in image_analysis_result and len(image_analysis_result["text"]) > 0:
formatted_result.append("Text: " + ", ".join(image_analysis_result["text"]))
if "dense_captions" in image_analysis_result:
formatted_result.append(
"Dense Captions: " + ", ".join(image_analysis_result["dense_captions"])
)
if "smart_crops" in image_analysis_result:
formatted_result.append(
"Smart Crops: " + ", ".join(image_analysis_result["smart_crops"])
)
if "people" in image_analysis_result:
formatted_result.append(
"People: " + ", ".join(image_analysis_result["people"])
)
return "\n".join(formatted_result)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
image_analysis_result = self._image_analysis(query)
if not image_analysis_result:
return "No good image analysis result was found"
return self._format_image_analysis_result(image_analysis_result)
except Exception as e:
raise RuntimeError(f"Error while running AzureAiImageAnalysisTool: {e}")

View File

@@ -0,0 +1,123 @@
from __future__ import annotations
import logging
import time
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
from langchain_community.tools.azure_ai_services.utils import (
detect_file_src_type,
download_audio_from_url,
)
logger = logging.getLogger(__name__)
class AzureAiServicesSpeechToTextTool(BaseTool):
"""Tool that queries the Azure AI Services Speech to Text API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/ai-services/speech-service/get-started-speech-to-text?pivots=programming-language-python
"""
azure_ai_services_key: str = "" #: :meta private:
azure_ai_services_region: str = "" #: :meta private:
speech_language: str = "en-US" #: :meta private:
speech_config: Any #: :meta private:
name: str = "azure_ai_services_speech_to_text"
description: str = (
"A wrapper around Azure AI Services Speech to Text. "
"Useful for when you need to transcribe audio to text. "
"Input should be a url to an audio file."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_ai_services_key = get_from_dict_or_env(
values, "azure_ai_services_key", "AZURE_AI_SERVICES_KEY"
)
azure_ai_services_region = get_from_dict_or_env(
values, "azure_ai_services_region", "AZURE_AI_SERVICES_REGION"
)
try:
import azure.cognitiveservices.speech as speechsdk
values["speech_config"] = speechsdk.SpeechConfig(
subscription=azure_ai_services_key, region=azure_ai_services_region
)
except ImportError:
raise ImportError(
"azure-cognitiveservices-speech is not installed. "
"Run `pip install azure-cognitiveservices-speech` to install."
)
return values
def _continuous_recognize(self, speech_recognizer: Any) -> str:
done = False
text = ""
def stop_cb(evt: Any) -> None:
"""callback that stop continuous recognition"""
speech_recognizer.stop_continuous_recognition_async()
nonlocal done
done = True
def retrieve_cb(evt: Any) -> None:
"""callback that retrieves the intermediate recognition results"""
nonlocal text
text += evt.result.text
# retrieve text on recognized events
speech_recognizer.recognized.connect(retrieve_cb)
# stop continuous recognition on either session stopped or canceled events
speech_recognizer.session_stopped.connect(stop_cb)
speech_recognizer.canceled.connect(stop_cb)
# Start continuous speech recognition
speech_recognizer.start_continuous_recognition_async()
while not done:
time.sleep(0.5)
return text
def _speech_to_text(self, audio_path: str, speech_language: str) -> str:
try:
import azure.cognitiveservices.speech as speechsdk
except ImportError:
pass
audio_src_type = detect_file_src_type(audio_path)
if audio_src_type == "local":
audio_config = speechsdk.AudioConfig(filename=audio_path)
elif audio_src_type == "remote":
tmp_audio_path = download_audio_from_url(audio_path)
audio_config = speechsdk.AudioConfig(filename=tmp_audio_path)
else:
raise ValueError(f"Invalid audio path: {audio_path}")
self.speech_config.speech_recognition_language = speech_language
speech_recognizer = speechsdk.SpeechRecognizer(self.speech_config, audio_config)
return self._continuous_recognize(speech_recognizer)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
text = self._speech_to_text(query, self.speech_language)
return text
except Exception as e:
raise RuntimeError(
f"Error while running AzureAiServicesSpeechToTextTool: {e}"
)

View File

@@ -0,0 +1,105 @@
from __future__ import annotations
import logging
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
logger = logging.getLogger(__name__)
class AzureAiServicesTextAnalyticsForHealthTool(BaseTool):
"""Tool that queries the Azure AI Services Text Analytics for Health API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/ai-services/language-service/text-analytics-for-health/quickstart?pivots=programming-language-python
"""
azure_ai_services_key: str = "" #: :meta private:
azure_ai_services_endpoint: str = "" #: :meta private:
text_analytics_client: Any #: :meta private:
name: str = "azure_ai_services_text_analytics_for_health"
description: str = (
"A wrapper around Azure AI Services Text Analytics for Health. "
"Useful for when you need to identify entities in healthcare data. "
"Input should be text."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_ai_services_key = get_from_dict_or_env(
values, "azure_ai_services_key", "AZURE_AI_SERVICES_KEY"
)
azure_ai_services_endpoint = get_from_dict_or_env(
values, "azure_ai_services_endpoint", "AZURE_AI_SERVICES_ENDPOINT"
)
try:
import azure.ai.textanalytics as sdk
from azure.core.credentials import AzureKeyCredential
values["text_analytics_client"] = sdk.TextAnalyticsClient(
endpoint=azure_ai_services_endpoint,
credential=AzureKeyCredential(azure_ai_services_key),
)
except ImportError:
raise ImportError(
"azure-ai-textanalytics is not installed. "
"Run `pip install azure-ai-textanalytics` to install."
)
return values
def _text_analysis(self, text: str) -> Dict:
poller = self.text_analytics_client.begin_analyze_healthcare_entities(
[{"id": "1", "language": "en", "text": text}]
)
result = poller.result()
res_dict = {}
docs = [doc for doc in result if not doc.is_error]
if docs is not None:
res_dict["entities"] = [
f"{x.text} is a healthcare entity of type {x.category}"
for y in docs
for x in y.entities
]
return res_dict
def _format_text_analysis_result(self, text_analysis_result: Dict) -> str:
formatted_result = []
if "entities" in text_analysis_result:
formatted_result.append(
f"""The text contains the following healthcare entities: {
", ".join(text_analysis_result["entities"])
}""".replace("\n", " ")
)
return "\n".join(formatted_result)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
text_analysis_result = self._text_analysis(query)
return self._format_text_analysis_result(text_analysis_result)
except Exception as e:
raise RuntimeError(
f"Error while running AzureAiServicesTextAnalyticsForHealthTool: {e}"
)

View File

@@ -0,0 +1,106 @@
from __future__ import annotations
import logging
import tempfile
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
logger = logging.getLogger(__name__)
class AzureAiServicesTextToSpeechTool(BaseTool):
"""Tool that queries the Azure AI Services Text to Speech API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/ai-services/speech-service/get-started-text-to-speech?pivots=programming-language-python
"""
name: str = "azure_ai_services_text_to_speech"
description: str = (
"A wrapper around Azure AI Services Text to Speech API. "
"Useful for when you need to convert text to speech. "
)
return_direct: bool = True
azure_ai_services_key: str = "" #: :meta private:
azure_ai_services_region: str = "" #: :meta private:
speech_language: str = "en-US" #: :meta private:
speech_config: Any #: :meta private:
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_ai_services_key = get_from_dict_or_env(
values, "azure_ai_services_key", "AZURE_AI_SERVICES_KEY"
)
azure_ai_services_region = get_from_dict_or_env(
values, "azure_ai_services_region", "AZURE_AI_SERVICES_REGION"
)
try:
import azure.cognitiveservices.speech as speechsdk
values["speech_config"] = speechsdk.SpeechConfig(
subscription=azure_ai_services_key, region=azure_ai_services_region
)
except ImportError:
raise ImportError(
"azure-cognitiveservices-speech is not installed. "
"Run `pip install azure-cognitiveservices-speech` to install."
)
return values
def _text_to_speech(self, text: str, speech_language: str) -> str:
try:
import azure.cognitiveservices.speech as speechsdk
except ImportError:
pass
self.speech_config.speech_synthesis_language = speech_language
speech_synthesizer = speechsdk.SpeechSynthesizer(
speech_config=self.speech_config, audio_config=None
)
result = speech_synthesizer.speak_text(text)
if result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted:
stream = speechsdk.AudioDataStream(result)
with tempfile.NamedTemporaryFile(
mode="wb", suffix=".wav", delete=False
) as f:
stream.save_to_wav_file(f.name)
return f.name
elif result.reason == speechsdk.ResultReason.Canceled:
cancellation_details = result.cancellation_details
logger.debug(f"Speech synthesis canceled: {cancellation_details.reason}")
if cancellation_details.reason == speechsdk.CancellationReason.Error:
raise RuntimeError(
f"Speech synthesis error: {cancellation_details.error_details}"
)
return "Speech synthesis canceled."
else:
return f"Speech synthesis failed: {result.reason}"
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
speech_file = self._text_to_speech(query, self.speech_language)
return speech_file
except Exception as e:
raise RuntimeError(
f"Error while running AzureAiServicesTextToSpeechTool: {e}"
)

View File

@@ -0,0 +1,29 @@
import os
import tempfile
from urllib.parse import urlparse
import requests
def detect_file_src_type(file_path: str) -> str:
"""Detect if the file is local or remote."""
if os.path.isfile(file_path):
return "local"
parsed_url = urlparse(file_path)
if parsed_url.scheme and parsed_url.netloc:
return "remote"
return "invalid"
def download_audio_from_url(audio_url: str) -> str:
"""Download audio from url to local."""
ext = audio_url.split(".")[-1]
response = requests.get(audio_url, stream=True)
response.raise_for_status()
with tempfile.NamedTemporaryFile(mode="wb", suffix=f".{ext}", delete=False) as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return f.name

View File

@@ -0,0 +1,25 @@
"""Azure Cognitive Services Tools."""
from langchain_community.tools.azure_cognitive_services.form_recognizer import (
AzureCogsFormRecognizerTool,
)
from langchain_community.tools.azure_cognitive_services.image_analysis import (
AzureCogsImageAnalysisTool,
)
from langchain_community.tools.azure_cognitive_services.speech2text import (
AzureCogsSpeech2TextTool,
)
from langchain_community.tools.azure_cognitive_services.text2speech import (
AzureCogsText2SpeechTool,
)
from langchain_community.tools.azure_cognitive_services.text_analytics_health import (
AzureCogsTextAnalyticsHealthTool,
)
__all__ = [
"AzureCogsImageAnalysisTool",
"AzureCogsFormRecognizerTool",
"AzureCogsSpeech2TextTool",
"AzureCogsText2SpeechTool",
"AzureCogsTextAnalyticsHealthTool",
]

View File

@@ -0,0 +1,144 @@
from __future__ import annotations
import logging
from typing import Any, Dict, List, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
from langchain_community.tools.azure_cognitive_services.utils import (
detect_file_src_type,
)
logger = logging.getLogger(__name__)
class AzureCogsFormRecognizerTool(BaseTool):
"""Tool that queries the Azure Cognitive Services Form Recognizer API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/applied-ai-services/form-recognizer/quickstarts/get-started-sdks-rest-api?view=form-recog-3.0.0&pivots=programming-language-python
"""
azure_cogs_key: str = "" #: :meta private:
azure_cogs_endpoint: str = "" #: :meta private:
doc_analysis_client: Any #: :meta private:
name: str = "azure_cognitive_services_form_recognizer"
description: str = (
"A wrapper around Azure Cognitive Services Form Recognizer. "
"Useful for when you need to "
"extract text, tables, and key-value pairs from documents. "
"Input should be a url to a document."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_cogs_key = get_from_dict_or_env(
values, "azure_cogs_key", "AZURE_COGS_KEY"
)
azure_cogs_endpoint = get_from_dict_or_env(
values, "azure_cogs_endpoint", "AZURE_COGS_ENDPOINT"
)
try:
from azure.ai.formrecognizer import DocumentAnalysisClient
from azure.core.credentials import AzureKeyCredential
values["doc_analysis_client"] = DocumentAnalysisClient(
endpoint=azure_cogs_endpoint,
credential=AzureKeyCredential(azure_cogs_key),
)
except ImportError:
raise ImportError(
"azure-ai-formrecognizer is not installed. "
"Run `pip install azure-ai-formrecognizer` to install."
)
return values
def _parse_tables(self, tables: List[Any]) -> List[Any]:
result = []
for table in tables:
rc, cc = table.row_count, table.column_count
_table = [["" for _ in range(cc)] for _ in range(rc)]
for cell in table.cells:
_table[cell.row_index][cell.column_index] = cell.content
result.append(_table)
return result
def _parse_kv_pairs(self, kv_pairs: List[Any]) -> List[Any]:
result = []
for kv_pair in kv_pairs:
key = kv_pair.key.content if kv_pair.key else ""
value = kv_pair.value.content if kv_pair.value else ""
result.append((key, value))
return result
def _document_analysis(self, document_path: str) -> Dict:
document_src_type = detect_file_src_type(document_path)
if document_src_type == "local":
with open(document_path, "rb") as document:
poller = self.doc_analysis_client.begin_analyze_document(
"prebuilt-document", document
)
elif document_src_type == "remote":
poller = self.doc_analysis_client.begin_analyze_document_from_url(
"prebuilt-document", document_path
)
else:
raise ValueError(f"Invalid document path: {document_path}")
result = poller.result()
res_dict = {}
if result.content is not None:
res_dict["content"] = result.content
if result.tables is not None:
res_dict["tables"] = self._parse_tables(result.tables)
if result.key_value_pairs is not None:
res_dict["key_value_pairs"] = self._parse_kv_pairs(result.key_value_pairs)
return res_dict
def _format_document_analysis_result(self, document_analysis_result: Dict) -> str:
formatted_result = []
if "content" in document_analysis_result:
formatted_result.append(
f"Content: {document_analysis_result['content']}".replace("\n", " ")
)
if "tables" in document_analysis_result:
for i, table in enumerate(document_analysis_result["tables"]):
formatted_result.append(f"Table {i}: {table}".replace("\n", " "))
if "key_value_pairs" in document_analysis_result:
for kv_pair in document_analysis_result["key_value_pairs"]:
formatted_result.append(
f"{kv_pair[0]}: {kv_pair[1]}".replace("\n", " ")
)
return "\n".join(formatted_result)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
document_analysis_result = self._document_analysis(query)
if not document_analysis_result:
return "No good document analysis result was found"
return self._format_document_analysis_result(document_analysis_result)
except Exception as e:
raise RuntimeError(f"Error while running AzureCogsFormRecognizerTool: {e}")

View File

@@ -0,0 +1,148 @@
from __future__ import annotations
import logging
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
from langchain_community.tools.azure_cognitive_services.utils import (
detect_file_src_type,
)
logger = logging.getLogger(__name__)
class AzureCogsImageAnalysisTool(BaseTool):
"""Tool that queries the Azure Cognitive Services Image Analysis API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts-sdk/image-analysis-client-library-40
"""
azure_cogs_key: str = "" #: :meta private:
azure_cogs_endpoint: str = "" #: :meta private:
vision_service: Any #: :meta private:
analysis_options: Any #: :meta private:
name: str = "azure_cognitive_services_image_analysis"
description: str = (
"A wrapper around Azure Cognitive Services Image Analysis. "
"Useful for when you need to analyze images. "
"Input should be a url to an image."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_cogs_key = get_from_dict_or_env(
values, "azure_cogs_key", "AZURE_COGS_KEY"
)
azure_cogs_endpoint = get_from_dict_or_env(
values, "azure_cogs_endpoint", "AZURE_COGS_ENDPOINT"
)
try:
import azure.ai.vision as sdk
values["vision_service"] = sdk.VisionServiceOptions(
endpoint=azure_cogs_endpoint, key=azure_cogs_key
)
values["analysis_options"] = sdk.ImageAnalysisOptions()
values["analysis_options"].features = (
sdk.ImageAnalysisFeature.CAPTION
| sdk.ImageAnalysisFeature.OBJECTS
| sdk.ImageAnalysisFeature.TAGS
| sdk.ImageAnalysisFeature.TEXT
)
except ImportError:
raise ImportError(
"azure-ai-vision is not installed. "
"Run `pip install azure-ai-vision` to install."
)
return values
def _image_analysis(self, image_path: str) -> Dict:
try:
import azure.ai.vision as sdk
except ImportError:
pass
image_src_type = detect_file_src_type(image_path)
if image_src_type == "local":
vision_source = sdk.VisionSource(filename=image_path)
elif image_src_type == "remote":
vision_source = sdk.VisionSource(url=image_path)
else:
raise ValueError(f"Invalid image path: {image_path}")
image_analyzer = sdk.ImageAnalyzer(
self.vision_service, vision_source, self.analysis_options
)
result = image_analyzer.analyze()
res_dict = {}
if result.reason == sdk.ImageAnalysisResultReason.ANALYZED:
if result.caption is not None:
res_dict["caption"] = result.caption.content
if result.objects is not None:
res_dict["objects"] = [obj.name for obj in result.objects]
if result.tags is not None:
res_dict["tags"] = [tag.name for tag in result.tags]
if result.text is not None:
res_dict["text"] = [line.content for line in result.text.lines]
else:
error_details = sdk.ImageAnalysisErrorDetails.from_result(result)
raise RuntimeError(
f"Image analysis failed.\n"
f"Reason: {error_details.reason}\n"
f"Details: {error_details.message}"
)
return res_dict
def _format_image_analysis_result(self, image_analysis_result: Dict) -> str:
formatted_result = []
if "caption" in image_analysis_result:
formatted_result.append("Caption: " + image_analysis_result["caption"])
if (
"objects" in image_analysis_result
and len(image_analysis_result["objects"]) > 0
):
formatted_result.append(
"Objects: " + ", ".join(image_analysis_result["objects"])
)
if "tags" in image_analysis_result and len(image_analysis_result["tags"]) > 0:
formatted_result.append("Tags: " + ", ".join(image_analysis_result["tags"]))
if "text" in image_analysis_result and len(image_analysis_result["text"]) > 0:
formatted_result.append("Text: " + ", ".join(image_analysis_result["text"]))
return "\n".join(formatted_result)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
image_analysis_result = self._image_analysis(query)
if not image_analysis_result:
return "No good image analysis result was found"
return self._format_image_analysis_result(image_analysis_result)
except Exception as e:
raise RuntimeError(f"Error while running AzureCogsImageAnalysisTool: {e}")

View File

@@ -0,0 +1,121 @@
from __future__ import annotations
import logging
import time
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
from langchain_community.tools.azure_cognitive_services.utils import (
detect_file_src_type,
download_audio_from_url,
)
logger = logging.getLogger(__name__)
class AzureCogsSpeech2TextTool(BaseTool):
"""Tool that queries the Azure Cognitive Services Speech2Text API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/get-started-speech-to-text?pivots=programming-language-python
"""
azure_cogs_key: str = "" #: :meta private:
azure_cogs_region: str = "" #: :meta private:
speech_language: str = "en-US" #: :meta private:
speech_config: Any #: :meta private:
name: str = "azure_cognitive_services_speech2text"
description: str = (
"A wrapper around Azure Cognitive Services Speech2Text. "
"Useful for when you need to transcribe audio to text. "
"Input should be a url to an audio file."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_cogs_key = get_from_dict_or_env(
values, "azure_cogs_key", "AZURE_COGS_KEY"
)
azure_cogs_region = get_from_dict_or_env(
values, "azure_cogs_region", "AZURE_COGS_REGION"
)
try:
import azure.cognitiveservices.speech as speechsdk
values["speech_config"] = speechsdk.SpeechConfig(
subscription=azure_cogs_key, region=azure_cogs_region
)
except ImportError:
raise ImportError(
"azure-cognitiveservices-speech is not installed. "
"Run `pip install azure-cognitiveservices-speech` to install."
)
return values
def _continuous_recognize(self, speech_recognizer: Any) -> str:
done = False
text = ""
def stop_cb(evt: Any) -> None:
"""callback that stop continuous recognition"""
speech_recognizer.stop_continuous_recognition_async()
nonlocal done
done = True
def retrieve_cb(evt: Any) -> None:
"""callback that retrieves the intermediate recognition results"""
nonlocal text
text += evt.result.text
# retrieve text on recognized events
speech_recognizer.recognized.connect(retrieve_cb)
# stop continuous recognition on either session stopped or canceled events
speech_recognizer.session_stopped.connect(stop_cb)
speech_recognizer.canceled.connect(stop_cb)
# Start continuous speech recognition
speech_recognizer.start_continuous_recognition_async()
while not done:
time.sleep(0.5)
return text
def _speech2text(self, audio_path: str, speech_language: str) -> str:
try:
import azure.cognitiveservices.speech as speechsdk
except ImportError:
pass
audio_src_type = detect_file_src_type(audio_path)
if audio_src_type == "local":
audio_config = speechsdk.AudioConfig(filename=audio_path)
elif audio_src_type == "remote":
tmp_audio_path = download_audio_from_url(audio_path)
audio_config = speechsdk.AudioConfig(filename=tmp_audio_path)
else:
raise ValueError(f"Invalid audio path: {audio_path}")
self.speech_config.speech_recognition_language = speech_language
speech_recognizer = speechsdk.SpeechRecognizer(self.speech_config, audio_config)
return self._continuous_recognize(speech_recognizer)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
text = self._speech2text(query, self.speech_language)
return text
except Exception as e:
raise RuntimeError(f"Error while running AzureCogsSpeech2TextTool: {e}")

View File

@@ -0,0 +1,103 @@
from __future__ import annotations
import logging
import tempfile
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
logger = logging.getLogger(__name__)
class AzureCogsText2SpeechTool(BaseTool):
"""Tool that queries the Azure Cognitive Services Text2Speech API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/get-started-text-to-speech?pivots=programming-language-python
"""
azure_cogs_key: str = "" #: :meta private:
azure_cogs_region: str = "" #: :meta private:
speech_language: str = "en-US" #: :meta private:
speech_config: Any #: :meta private:
name: str = "azure_cognitive_services_text2speech"
description: str = (
"A wrapper around Azure Cognitive Services Text2Speech. "
"Useful for when you need to convert text to speech. "
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_cogs_key = get_from_dict_or_env(
values, "azure_cogs_key", "AZURE_COGS_KEY"
)
azure_cogs_region = get_from_dict_or_env(
values, "azure_cogs_region", "AZURE_COGS_REGION"
)
try:
import azure.cognitiveservices.speech as speechsdk
values["speech_config"] = speechsdk.SpeechConfig(
subscription=azure_cogs_key, region=azure_cogs_region
)
except ImportError:
raise ImportError(
"azure-cognitiveservices-speech is not installed. "
"Run `pip install azure-cognitiveservices-speech` to install."
)
return values
def _text2speech(self, text: str, speech_language: str) -> str:
try:
import azure.cognitiveservices.speech as speechsdk
except ImportError:
pass
self.speech_config.speech_synthesis_language = speech_language
speech_synthesizer = speechsdk.SpeechSynthesizer(
speech_config=self.speech_config, audio_config=None
)
result = speech_synthesizer.speak_text(text)
if result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted:
stream = speechsdk.AudioDataStream(result)
with tempfile.NamedTemporaryFile(
mode="wb", suffix=".wav", delete=False
) as f:
stream.save_to_wav_file(f.name)
return f.name
elif result.reason == speechsdk.ResultReason.Canceled:
cancellation_details = result.cancellation_details
logger.debug(f"Speech synthesis canceled: {cancellation_details.reason}")
if cancellation_details.reason == speechsdk.CancellationReason.Error:
raise RuntimeError(
f"Speech synthesis error: {cancellation_details.error_details}"
)
return "Speech synthesis canceled."
else:
return f"Speech synthesis failed: {result.reason}"
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
speech_file = self._text2speech(query, self.speech_language)
return speech_file
except Exception as e:
raise RuntimeError(f"Error while running AzureCogsText2SpeechTool: {e}")

View File

@@ -0,0 +1,105 @@
from __future__ import annotations
import logging
from typing import Any, Dict, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_core.utils import get_from_dict_or_env
from pydantic import model_validator
logger = logging.getLogger(__name__)
class AzureCogsTextAnalyticsHealthTool(BaseTool):
"""Tool that queries the Azure Cognitive Services Text Analytics for Health API.
In order to set this up, follow instructions at:
https://learn.microsoft.com/en-us/azure/ai-services/language-service/text-analytics-for-health/quickstart?tabs=windows&pivots=programming-language-python
"""
azure_cogs_key: str = "" #: :meta private:
azure_cogs_endpoint: str = "" #: :meta private:
text_analytics_client: Any #: :meta private:
name: str = "azure_cognitive_services_text_analyics_health"
description: str = (
"A wrapper around Azure Cognitive Services Text Analytics for Health. "
"Useful for when you need to identify entities in healthcare data. "
"Input should be text."
)
@model_validator(mode="before")
@classmethod
def validate_environment(cls, values: Dict) -> Any:
"""Validate that api key and endpoint exists in environment."""
azure_cogs_key = get_from_dict_or_env(
values, "azure_cogs_key", "AZURE_COGS_KEY"
)
azure_cogs_endpoint = get_from_dict_or_env(
values, "azure_cogs_endpoint", "AZURE_COGS_ENDPOINT"
)
try:
import azure.ai.textanalytics as sdk
from azure.core.credentials import AzureKeyCredential
values["text_analytics_client"] = sdk.TextAnalyticsClient(
endpoint=azure_cogs_endpoint,
credential=AzureKeyCredential(azure_cogs_key),
)
except ImportError:
raise ImportError(
"azure-ai-textanalytics is not installed. "
"Run `pip install azure-ai-textanalytics` to install."
)
return values
def _text_analysis(self, text: str) -> Dict:
poller = self.text_analytics_client.begin_analyze_healthcare_entities(
[{"id": "1", "language": "en", "text": text}]
)
result = poller.result()
res_dict = {}
docs = [doc for doc in result if not doc.is_error]
if docs is not None:
res_dict["entities"] = [
f"{x.text} is a healthcare entity of type {x.category}"
for y in docs
for x in y.entities
]
return res_dict
def _format_text_analysis_result(self, text_analysis_result: Dict) -> str:
formatted_result = []
if "entities" in text_analysis_result:
formatted_result.append(
f"""The text contains the following healthcare entities: {
", ".join(text_analysis_result["entities"])
}""".replace("\n", " ")
)
return "\n".join(formatted_result)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
try:
text_analysis_result = self._text_analysis(query)
return self._format_text_analysis_result(text_analysis_result)
except Exception as e:
raise RuntimeError(
f"Error while running AzureCogsTextAnalyticsHealthTool: {e}"
)

View File

@@ -0,0 +1,29 @@
import os
import tempfile
from urllib.parse import urlparse
import requests
def detect_file_src_type(file_path: str) -> str:
"""Detect if the file is local or remote."""
if os.path.isfile(file_path):
return "local"
parsed_url = urlparse(file_path)
if parsed_url.scheme and parsed_url.netloc:
return "remote"
return "invalid"
def download_audio_from_url(audio_url: str) -> str:
"""Download audio from url to local."""
ext = audio_url.split(".")[-1]
response = requests.get(audio_url, stream=True)
response.raise_for_status()
with tempfile.NamedTemporaryFile(mode="wb", suffix=f".{ext}", delete=False) as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return f.name

View File

@@ -0,0 +1,165 @@
import base64
import itertools
import json
import re
from pathlib import Path
from typing import Dict, List, Type
import requests
from langchain_core.tools import Tool
from pydantic import BaseModel, Field
def strip_markdown_code(md_string: str) -> str:
"""Strip markdown code from a string."""
stripped_string = re.sub(r"^`{1,3}.*?\n", "", md_string, flags=re.DOTALL)
stripped_string = re.sub(r"`{1,3}$", "", stripped_string)
return stripped_string
def head_file(path: str, n: int) -> List[str]:
"""Get the first n lines of a file."""
try:
with open(path, "r") as f:
return [str(line) for line in itertools.islice(f, n)]
except Exception:
return []
def file_to_base64(path: str) -> str:
"""Convert a file to base64."""
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()
class BearlyInterpreterToolArguments(BaseModel):
"""Arguments for the BearlyInterpreterTool."""
python_code: str = Field(
...,
examples=["print('Hello World')"],
description=(
"The pure python script to be evaluated. "
"The contents will be in main.py. "
"It should not be in markdown format."
),
)
base_description = """Evaluates python code in a sandbox environment. \
The environment resets on every execution. \
You must send the whole script every time and print your outputs. \
Script should be pure python code that can be evaluated. \
It should be in python format NOT markdown. \
The code should NOT be wrapped in backticks. \
All python packages including requests, matplotlib, scipy, numpy, pandas, \
etc are available. \
If you have any files outputted write them to "output/" relative to the execution \
path. Output can only be read from the directory, stdout, and stdin. \
Do not use things like plot.show() as it will \
not work instead write them out `output/` and a link to the file will be returned. \
print() any output and results so you can capture the output."""
class FileInfo(BaseModel):
"""Information about a file to be uploaded."""
source_path: str
description: str
target_path: str
class BearlyInterpreterTool:
"""Tool for evaluating python code in a sandbox environment."""
api_key: str
endpoint: str = "https://exec.bearly.ai/v1/interpreter"
name: str = "bearly_interpreter"
args_schema: Type[BaseModel] = BearlyInterpreterToolArguments
files: Dict[str, FileInfo] = {}
def __init__(self, api_key: str):
self.api_key = api_key
@property
def file_description(self) -> str:
if len(self.files) == 0:
return ""
lines = ["The following files available in the evaluation environment:"]
for target_path, file_info in self.files.items():
peek_content = head_file(file_info.source_path, 4)
lines.append(
f"- path: `{target_path}` \n first four lines: {peek_content}"
f" \n description: `{file_info.description}`"
)
return "\n".join(lines)
@property
def description(self) -> str:
return (base_description + "\n\n" + self.file_description).strip()
def make_input_files(self) -> List[dict]:
files = []
for target_path, file_info in self.files.items():
files.append(
{
"pathname": target_path,
"contentsBasesixtyfour": file_to_base64(file_info.source_path),
}
)
return files
def _run(self, python_code: str) -> dict:
script = strip_markdown_code(python_code)
resp = requests.post(
"https://exec.bearly.ai/v1/interpreter",
data=json.dumps(
{
"fileContents": script,
"inputFiles": self.make_input_files(),
"outputDir": "output/",
"outputAsLinks": True,
}
),
headers={"Authorization": self.api_key},
).json()
return {
"stdout": (
base64.b64decode(resp["stdoutBasesixtyfour"]).decode()
if resp["stdoutBasesixtyfour"]
else ""
),
"stderr": (
base64.b64decode(resp["stderrBasesixtyfour"]).decode()
if resp["stderrBasesixtyfour"]
else ""
),
"fileLinks": resp["fileLinks"],
"exitCode": resp["exitCode"],
}
async def _arun(self, query: str) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("custom_search does not support async")
def add_file(self, source_path: str, target_path: str, description: str) -> None:
if target_path in self.files:
raise ValueError("target_path already exists")
if not Path(source_path).exists():
raise ValueError("source_path does not exist")
self.files[target_path] = FileInfo(
target_path=target_path, source_path=source_path, description=description
)
def clear_files(self) -> None:
self.files = {}
# TODO: this is because we can't have a dynamic description
# because of the base pydantic class
def as_tool(self) -> Tool:
return Tool.from_function(
func=self._run,
name=self.name,
description=self.description,
args_schema=self.args_schema,
)

View File

@@ -0,0 +1,5 @@
"""Bing Search API toolkit."""
from langchain_community.tools.bing_search.tool import BingSearchResults, BingSearchRun
__all__ = ["BingSearchRun", "BingSearchResults"]

View File

@@ -0,0 +1,98 @@
"""Tool for the Bing search API."""
from typing import Dict, List, Literal, Optional, Tuple
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from langchain_community.utilities.bing_search import BingSearchAPIWrapper
class BingSearchRun(BaseTool):
"""Tool that queries the Bing search API."""
name: str = "bing_search"
description: str = (
"A wrapper around Bing Search. "
"Useful for when you need to answer questions about current events. "
"Input should be a search query."
)
api_wrapper: BingSearchAPIWrapper
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
return self.api_wrapper.run(query)
class BingSearchResults(BaseTool):
"""Bing Search tool.
Setup:
Install ``langchain-community`` and set environment variable ``BING_SUBSCRIPTION_KEY``.
.. code-block:: bash
pip install -U langchain-community
export BING_SUBSCRIPTION_KEY="your-api-key"
Instantiation:
.. code-block:: python
from langchain_community.tools.bing_search import BingSearchResults
from langchain_community.utilities import BingSearchAPIWrapper
api_wrapper = BingSearchAPIWrapper()
tool = BingSearchResults(api_wrapper=api_wrapper)
Invocation with args:
.. code-block:: python
tool.invoke({"query": "what is the weather in SF?"})
.. code-block:: python
"[{'snippet': '<b>San Francisco, CA</b> <b>Weather</b> Forecast, with current conditions, wind, air quality, and what to expect for the next 3 days.', 'title': 'San Francisco, CA Weather Forecast | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629'}, {'snippet': 'Tropical Storm Ernesto Forms; Fire <b>Weather</b> Concerns in the Great Basin: Hot Temperatures Return to the South-Central U.S. ... <b>San Francisco CA</b> 37.77°N 122.41°W (Elev. 131 ft) Last Update: 2:21 pm PDT Aug 12, 2024. Forecast Valid: 6pm PDT Aug 12, 2024-6pm PDT Aug 19, 2024 .', 'title': 'National Weather Service', 'link': 'https://forecast.weather.gov/zipcity.php?inputstring=San+Francisco,CA'}, {'snippet': 'Current <b>weather</b> <b>in San Francisco, CA</b>. Check current conditions <b>in San Francisco, CA</b> with radar, hourly, and more.', 'title': 'San Francisco, CA Current Weather | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629'}, {'snippet': 'Everything you need to know about today&#39;s <b>weather</b> <b>in San Francisco, CA</b>. High/Low, Precipitation Chances, Sunrise/Sunset, and today&#39;s Temperature History.', 'title': 'Weather Today for San Francisco, CA | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/weather-today/347629'}]"
Invocation with ToolCall:
.. code-block:: python
tool.invoke({"args": {"query":"what is the weather in SF?"}, "id": "1", "name": tool.name, "type": "tool_call"})
.. code-block:: python
ToolMessage(
content="[{'snippet': 'Get the latest <b>weather</b> forecast for <b>San Francisco, CA</b>, including temperature, RealFeel, and chance of precipitation. Find out how the <b>weather</b> will affect your plans and activities in the city of ...', 'title': 'San Francisco, CA Weather Forecast | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629'}, {'snippet': 'Radar. Be prepared with the most accurate 10-day forecast for <b>San Francisco, CA</b> with highs, lows, chance of precipitation from The <b>Weather</b> Channel and <b>Weather</b>.com.', 'title': '10-Day Weather Forecast for San Francisco, CA - The Weather Channel', 'link': 'https://weather.com/weather/tenday/l/San+Francisco+CA+USCA0987:1:US'}, {'snippet': 'Tropical Storm Ernesto Forms; Fire <b>Weather</b> Concerns in the Great Basin: Hot Temperatures Return to the South-Central U.S. ... <b>San Francisco CA</b> 37.77°N 122.41°W (Elev. 131 ft) Last Update: 2:21 pm PDT Aug 12, 2024. Forecast Valid: 6pm PDT Aug 12, 2024-6pm PDT Aug 19, 2024 .', 'title': 'National Weather Service', 'link': 'https://forecast.weather.gov/zipcity.php?inputstring=San+Francisco,CA'}, {'snippet': 'Current <b>weather</b> <b>in San Francisco, CA</b>. Check current conditions <b>in San Francisco, CA</b> with radar, hourly, and more.', 'title': 'San Francisco, CA Current Weather | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629'}]",
artifact=[{'snippet': 'Get the latest <b>weather</b> forecast for <b>San Francisco, CA</b>, including temperature, RealFeel, and chance of precipitation. Find out how the <b>weather</b> will affect your plans and activities in the city of ...', 'title': 'San Francisco, CA Weather Forecast | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629'}, {'snippet': 'Radar. Be prepared with the most accurate 10-day forecast for <b>San Francisco, CA</b> with highs, lows, chance of precipitation from The <b>Weather</b> Channel and <b>Weather</b>.com.', 'title': '10-Day Weather Forecast for San Francisco, CA - The Weather Channel', 'link': 'https://weather.com/weather/tenday/l/San+Francisco+CA+USCA0987:1:US'}, {'snippet': 'Tropical Storm Ernesto Forms; Fire <b>Weather</b> Concerns in the Great Basin: Hot Temperatures Return to the South-Central U.S. ... <b>San Francisco CA</b> 37.77°N 122.41°W (Elev. 131 ft) Last Update: 2:21 pm PDT Aug 12, 2024. Forecast Valid: 6pm PDT Aug 12, 2024-6pm PDT Aug 19, 2024 .', 'title': 'National Weather Service', 'link': 'https://forecast.weather.gov/zipcity.php?inputstring=San+Francisco,CA'}, {'snippet': 'Current <b>weather</b> <b>in San Francisco, CA</b>. Check current conditions <b>in San Francisco, CA</b> with radar, hourly, and more.', 'title': 'San Francisco, CA Current Weather | AccuWeather', 'link': 'https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629'}],
name='bing_search_results_json',
tool_call_id='1'
)
""" # noqa: E501
name: str = "bing_search_results_json"
description: str = (
"A wrapper around Bing Search. "
"Useful for when you need to answer questions about current events. "
"Input should be a search query. Output is an array of the query results."
)
num_results: int = 4
"""Max search results to return, default is 4."""
api_wrapper: BingSearchAPIWrapper
response_format: Literal["content_and_artifact"] = "content_and_artifact"
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> Tuple[str, List[Dict]]:
"""Use the tool."""
try:
results = self.api_wrapper.results(query, self.num_results)
return str(results), results
except Exception as e:
return repr(e), []

View File

@@ -0,0 +1,92 @@
from __future__ import annotations
from typing import Any, Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import Field, SecretStr
from langchain_community.utilities.brave_search import BraveSearchWrapper
class BraveSearch(BaseTool):
"""Tool that queries the BraveSearch.
Api key can be provided as an environment variable BRAVE_SEARCH_API_KEY
or as a parameter.
Example usages:
.. code-block:: python
# uses BRAVE_SEARCH_API_KEY from environment
tool = BraveSearch()
.. code-block:: python
# uses the provided api key
tool = BraveSearch.from_api_key("your-api-key")
.. code-block:: python
# uses the provided api key and search kwargs
tool = BraveSearch.from_api_key(
api_key = "your-api-key",
search_kwargs={"max_results": 5}
)
.. code-block:: python
# uses BRAVE_SEARCH_API_KEY from environment
tool = BraveSearch.from_search_kwargs({"max_results": 5})
"""
name: str = "brave_search"
description: str = (
"a search engine. "
"useful for when you need to answer questions about current events."
" input should be a search query."
)
search_wrapper: BraveSearchWrapper = Field(default_factory=BraveSearchWrapper)
@classmethod
def from_api_key(
cls, api_key: str, search_kwargs: Optional[dict] = None, **kwargs: Any
) -> BraveSearch:
"""Create a tool from an api key.
Args:
api_key: The api key to use.
search_kwargs: Any additional kwargs to pass to the search wrapper.
**kwargs: Any additional kwargs to pass to the tool.
Returns:
A tool.
"""
wrapper = BraveSearchWrapper(
api_key=SecretStr(api_key), search_kwargs=search_kwargs or {}
)
return cls(search_wrapper=wrapper, **kwargs)
@classmethod
def from_search_kwargs(cls, search_kwargs: dict, **kwargs: Any) -> BraveSearch:
"""Create a tool from search kwargs.
Uses the environment variable BRAVE_SEARCH_API_KEY for api key.
Args:
search_kwargs: Any additional kwargs to pass to the search wrapper.
**kwargs: Any additional kwargs to pass to the tool.
Returns:
A tool.
"""
# we can not provide api key because it's calculated in the wrapper,
# so the ignore is needed for linter
# not ideal but needed to keep the tool code changes non-breaking
wrapper = BraveSearchWrapper(search_kwargs=search_kwargs)
return cls(search_wrapper=wrapper, **kwargs)
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
return self.search_wrapper.run(query)

View File

@@ -0,0 +1 @@
"""Cassandra Tool"""

View File

@@ -0,0 +1,36 @@
"""Tools for interacting with an Apache Cassandra database."""
QUERY_PATH_PROMPT = """"
You are an Apache Cassandra expert query analysis bot with the following features
and rules:
- You will take a question from the end user about finding certain
data in the database.
- You will examine the schema of the database and create a query path.
- You will provide the user with the correct query to find the data they are looking
for showing the steps provided by the query path.
- You will use best practices for querying Apache Cassandra using partition keys
and clustering columns.
- Avoid using ALLOW FILTERING in the query.
- The goal is to find a query path, so it may take querying other tables to get
to the final answer.
The following is an example of a query path in JSON format:
{
"query_paths": [
{
"description": "Direct query to users table using email",
"steps": [
{
"table": "user_credentials",
"query":
"SELECT userid FROM user_credentials WHERE email = 'example@example.com';"
},
{
"table": "users",
"query": "SELECT * FROM users WHERE userid = ?;"
}
]
}
]
}"""

View File

@@ -0,0 +1,142 @@
"""Tools for interacting with an Apache Cassandra database."""
from __future__ import annotations
import traceback
from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence, Type, Union
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, ConfigDict, Field
from langchain_community.utilities.cassandra_database import CassandraDatabase
if TYPE_CHECKING:
from cassandra.cluster import ResultSet
class BaseCassandraDatabaseTool(BaseModel):
"""Base tool for interacting with an Apache Cassandra database."""
db: CassandraDatabase = Field(exclude=True)
model_config = ConfigDict(
arbitrary_types_allowed=True,
)
class _QueryCassandraDatabaseToolInput(BaseModel):
query: str = Field(..., description="A detailed and correct CQL query.")
class QueryCassandraDatabaseTool(BaseCassandraDatabaseTool, BaseTool):
"""Tool for querying an Apache Cassandra database with provided CQL."""
name: str = "cassandra_db_query"
description: str = """
Execute a CQL query against the database and get back the result.
If the query is not correct, an error message will be returned.
If an error is returned, rewrite the query, check the query, and try again.
"""
args_schema: Type[BaseModel] = _QueryCassandraDatabaseToolInput
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> Union[str, Sequence[Dict[str, Any]], ResultSet]:
"""Execute the query, return the results or an error message."""
try:
return self.db.run(query)
except Exception as e:
"""Format the error message"""
return f"Error: {e}\n{traceback.format_exc()}"
class _GetSchemaCassandraDatabaseToolInput(BaseModel):
keyspace: str = Field(
...,
description=("The name of the keyspace for which to return the schema."),
)
class GetSchemaCassandraDatabaseTool(BaseCassandraDatabaseTool, BaseTool):
"""Tool for getting the schema of a keyspace in an Apache Cassandra database."""
name: str = "cassandra_db_schema"
description: str = """
Input to this tool is a keyspace name, output is a table description
of Apache Cassandra tables.
If the query is not correct, an error message will be returned.
If an error is returned, report back to the user that the keyspace
doesn't exist and stop.
"""
args_schema: Type[BaseModel] = _GetSchemaCassandraDatabaseToolInput
def _run(
self,
keyspace: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Get the schema for a keyspace."""
try:
tables = self.db.get_keyspace_tables(keyspace)
return "".join([table.as_markdown() + "\n\n" for table in tables])
except Exception as e:
"""Format the error message"""
return f"Error: {e}\n{traceback.format_exc()}"
class _GetTableDataCassandraDatabaseToolInput(BaseModel):
keyspace: str = Field(
...,
description=("The name of the keyspace containing the table."),
)
table: str = Field(
...,
description=("The name of the table for which to return data."),
)
predicate: str = Field(
...,
description=("The predicate for the query that uses the primary key."),
)
limit: int = Field(
...,
description=("The maximum number of rows to return."),
)
class GetTableDataCassandraDatabaseTool(BaseCassandraDatabaseTool, BaseTool):
"""
Tool for getting data from a table in an Apache Cassandra database.
Use the WHERE clause to specify the predicate for the query that uses the
primary key. A blank predicate will return all rows. Avoid this if possible.
Use the limit to specify the number of rows to return. A blank limit will
return all rows.
"""
name: str = "cassandra_db_select_table_data"
description: str = """
Tool for getting data from a table in an Apache Cassandra database.
Use the WHERE clause to specify the predicate for the query that uses the
primary key. A blank predicate will return all rows. Avoid this if possible.
Use the limit to specify the number of rows to return. A blank limit will
return all rows.
"""
args_schema: Type[BaseModel] = _GetTableDataCassandraDatabaseToolInput
def _run(
self,
keyspace: str,
table: str,
predicate: str,
limit: int,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Get data from a table in a keyspace."""
try:
return self.db.get_table_data(keyspace, table, predicate, limit)
except Exception as e:
"""Format the error message"""
return f"Error: {e}\n{traceback.format_exc()}"

View File

@@ -0,0 +1,131 @@
# flake8: noqa
CLICKUP_TASK_CREATE_PROMPT = """
This tool is a wrapper around clickup's create_task API, useful when you need to create a CLICKUP task.
The input to this tool is a dictionary specifying the fields of the CLICKUP task, and will be passed into clickup's CLICKUP `create_task` function.
Only add fields described by the user.
Use the following mapping in order to map the user's priority to the clickup priority: {{
Urgent = 1,
High = 2,
Normal = 3,
Low = 4,
}}. If the user passes in "urgent" replace the priority value as 1.
Here are a few task descriptions and corresponding input examples:
Task: create a task called "Daily report"
Example Input: {{"name": "Daily report"}}
Task: Make an open task called "ClickUp toolkit refactor" with description "Refactor the clickup toolkit to use dataclasses for parsing", with status "open"
Example Input: {{"name": "ClickUp toolkit refactor", "description": "Refactor the clickup toolkit to use dataclasses for parsing", "status": "Open"}}
Task: create a task with priority 3 called "New Task Name" with description "New Task Description", with status "open"
Example Input: {{"name": "New Task Name", "description": "New Task Description", "status": "Open", "priority": 3}}
Task: Add a task called "Bob's task" and assign it to Bob (user id: 81928627)
Example Input: {{"name": "Bob's task", "description": "Task for Bob", "assignees": [81928627]}}
"""
CLICKUP_LIST_CREATE_PROMPT = """
This tool is a wrapper around clickup's create_list API, useful when you need to create a CLICKUP list.
The input to this tool is a dictionary specifying the fields of a clickup list, and will be passed to clickup's create_list function.
Only add fields described by the user.
Use the following mapping in order to map the user's priority to the clickup priority: {{
Urgent = 1,
High = 2,
Normal = 3,
Low = 4,
}}. If the user passes in "urgent" replace the priority value as 1.
Here are a few list descriptions and corresponding input examples:
Description: make a list with name "General List"
Example Input: {{"name": "General List"}}
Description: add a new list ("TODOs") with low priority
Example Input: {{"name": "General List", "priority": 4}}
Description: create a list with name "List name", content "List content", priority 2, and status "red"
Example Input: {{"name": "List name", "content": "List content", "priority": 2, "status": "red"}}
"""
CLICKUP_FOLDER_CREATE_PROMPT = """
This tool is a wrapper around clickup's create_folder API, useful when you need to create a CLICKUP folder.
The input to this tool is a dictionary specifying the fields of a clickup folder, and will be passed to clickup's create_folder function.
For example, to create a folder with name "Folder name" you would pass in the following dictionary:
{{
"name": "Folder name",
}}
"""
CLICKUP_GET_TASK_PROMPT = """
This tool is a wrapper around clickup's API,
Do NOT use to get a task specific attribute. Use get task attribute instead.
useful when you need to get a specific task for the user. Given the task id you want to create a request similar to the following dictionary:
payload = {{"task_id": "86a0t44tq"}}
"""
CLICKUP_GET_TASK_ATTRIBUTE_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to get a specific attribute from a task. Given the task id and desired attribute create a request similar to the following dictionary:
payload = {{"task_id": "<task_id_to_update>", "attribute_name": "<attribute_name_to_update>"}}
Here are some example queries their corresponding payloads:
Get the name of task 23jn23kjn -> {{"task_id": "23jn23kjn", "attribute_name": "name"}}
What is the priority of task 86a0t44tq? -> {{"task_id": "86a0t44tq", "attribute_name": "priority"}}
Output the description of task sdc9ds9jc -> {{"task_id": "sdc9ds9jc", "attribute_name": "description"}}
Who is assigned to task bgjfnbfg0 -> {{"task_id": "bgjfnbfg0", "attribute_name": "assignee"}}
Which is the status of task kjnsdcjc? -> {{"task_id": "kjnsdcjc", "attribute_name": "description"}}
How long is the time estimate of task sjncsd999? -> {{"task_id": "sjncsd999", "attribute_name": "time_estimate"}}
Is task jnsd98sd archived?-> {{"task_id": "jnsd98sd", "attribute_name": "archive"}}
"""
CLICKUP_GET_ALL_TEAMS_PROMPT = """
This tool is a wrapper around clickup's API, useful when you need to get all teams that the user is a part of.
To get a list of all the teams there is no necessary request parameters.
"""
CLICKUP_GET_LIST_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to get a specific list for the user. Given the list id you want to create a request similar to the following dictionary:
payload = {{"list_id": "901300608424"}}
"""
CLICKUP_GET_FOLDERS_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to get a specific folder for the user. Given the user's workspace id you want to create a request similar to the following dictionary:
payload = {{"folder_id": "90130119692"}}
"""
CLICKUP_GET_SPACES_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to get all the spaces available to a user. Given the user's workspace id you want to create a request similar to the following dictionary:
payload = {{"team_id": "90130119692"}}
"""
CLICKUP_GET_SPACES_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to get all the spaces available to a user. Given the user's workspace id you want to create a request similar to the following dictionary:
payload = {{"team_id": "90130119692"}}
"""
CLICKUP_UPDATE_TASK_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to update a specific attribute of a task. Given the task id, desired attribute to change and the new value you want to create a request similar to the following dictionary:
payload = {{"task_id": "<task_id_to_update>", "attribute_name": "<attribute_name_to_update>", "value": "<value_to_update_to>"}}
Here are some example queries their corresponding payloads:
Change the name of task 23jn23kjn to new task name -> {{"task_id": "23jn23kjn", "attribute_name": "name", "value": "new task name"}}
Update the priority of task 86a0t44tq to 1 -> {{"task_id": "86a0t44tq", "attribute_name": "priority", "value": 1}}
Re-write the description of task sdc9ds9jc to 'a new task description' -> {{"task_id": "sdc9ds9jc", "attribute_name": "description", "value": "a new task description"}}
Forward the status of task kjnsdcjc to done -> {{"task_id": "kjnsdcjc", "attribute_name": "description", "status": "done"}}
Increase the time estimate of task sjncsd999 to 3h -> {{"task_id": "sjncsd999", "attribute_name": "time_estimate", "value": 8000}}
Archive task jnsd98sd -> {{"task_id": "jnsd98sd", "attribute_name": "archive", "value": true}}
*IMPORTANT*: Pay attention to the exact syntax above and the correct use of quotes.
For changing priority and time estimates, we expect integers (int).
For name, description and status we expect strings (str).
For archive, we expect a boolean (bool).
"""
CLICKUP_UPDATE_TASK_ASSIGNEE_PROMPT = """
This tool is a wrapper around clickup's API,
useful when you need to update the assignees of a task. Given the task id, the operation add or remove (rem), and the list of user ids. You want to create a request similar to the following dictionary:
payload = {{"task_id": "<task_id_to_update>", "operation": "<operation, (add or rem)>", "users": [<user_id_1>, <user_id_2>]}}
Here are some example queries their corresponding payloads:
Add 81928627 and 3987234 as assignees to task 21hw21jn -> {{"task_id": "21hw21jn", "operation": "add", "users": [81928627, 3987234]}}
Remove 67823487 as assignee from task jin34ji4 -> {{"task_id": "jin34ji4", "operation": "rem", "users": [67823487]}}
*IMPORTANT*: Users id should always be ints.
"""

View File

@@ -0,0 +1,43 @@
"""
This tool allows agents to interact with the clickup library
and operate on a Clickup instance.
To use this tool, you must first set as environment variables:
client_secret
client_id
code
Below is a sample script that uses the Clickup tool:
```python
from langchain_community.agent_toolkits.clickup.toolkit import ClickupToolkit
from langchain_community.utilities.clickup import ClickupAPIWrapper
clickup = ClickupAPIWrapper()
toolkit = ClickupToolkit.from_clickup_api_wrapper(clickup)
```
"""
from typing import Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import Field
from langchain_community.utilities.clickup import ClickupAPIWrapper
class ClickupAction(BaseTool):
"""Tool that queries the Clickup API."""
api_wrapper: ClickupAPIWrapper = Field(default_factory=ClickupAPIWrapper)
mode: str
name: str = ""
description: str = ""
def _run(
self,
instructions: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the Clickup API to run an operation."""
return self.api_wrapper.run(self.mode, instructions)

View File

@@ -0,0 +1 @@
"Cogniswitch Tools"

Some files were not shown because too many files have changed in this diff Show More