initial commit
This commit is contained in:
664
venv/Lib/site-packages/langchain_community/tools/__init__.py
Normal file
664
venv/Lib/site-packages/langchain_community/tools/__init__.py
Normal 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}")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)}"
|
||||
@@ -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
|
||||
@@ -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)}"
|
||||
@@ -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)}"
|
||||
@@ -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)}"
|
||||
@@ -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
|
||||
@@ -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)}"
|
||||
@@ -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",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
from langchain_community.tools.arxiv.tool import ArxivQueryRun
|
||||
|
||||
"""Arxiv API toolkit."""
|
||||
"""Tool for the Arxiv Search API."""
|
||||
|
||||
__all__ = ["ArxivQueryRun"]
|
||||
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
@@ -0,0 +1,7 @@
|
||||
"""AskNews API toolkit."""
|
||||
|
||||
from langchain_community.tools.asknews.tool import (
|
||||
AskNewsSearch,
|
||||
)
|
||||
|
||||
__all__ = ["AskNewsSearch"]
|
||||
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
@@ -0,0 +1,7 @@
|
||||
from langchain_community.tools.audio.huggingface_text_to_speech_inference import (
|
||||
HuggingFaceTextToSpeechModelInference,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"HuggingFaceTextToSpeechModelInference",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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}"
|
||||
)
|
||||
@@ -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}")
|
||||
@@ -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}"
|
||||
)
|
||||
@@ -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}"
|
||||
)
|
||||
@@ -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}"
|
||||
)
|
||||
@@ -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
|
||||
@@ -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",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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}")
|
||||
@@ -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}")
|
||||
@@ -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}")
|
||||
@@ -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}")
|
||||
@@ -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}"
|
||||
)
|
||||
@@ -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
|
||||
Binary file not shown.
Binary file not shown.
165
venv/Lib/site-packages/langchain_community/tools/bearly/tool.py
Normal file
165
venv/Lib/site-packages/langchain_community/tools/bearly/tool.py
Normal 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,
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Bing Search API toolkit."""
|
||||
|
||||
from langchain_community.tools.bing_search.tool import BingSearchResults, BingSearchRun
|
||||
|
||||
__all__ = ["BingSearchRun", "BingSearchResults"]
|
||||
Binary file not shown.
Binary file not shown.
@@ -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's <b>weather</b> <b>in San Francisco, CA</b>. High/Low, Precipitation Chances, Sunrise/Sunset, and today'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), []
|
||||
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
"""Cassandra Tool"""
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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 = ?;"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}"""
|
||||
@@ -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()}"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
"""
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
"Cogniswitch Tools"
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user