Spaces:
Runtime error
Runtime error
| # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= | |
| from __future__ import annotations | |
| import json | |
| import logging | |
| import os | |
| from typing import TYPE_CHECKING, List, Optional | |
| from camel.toolkits.base import BaseToolkit | |
| if TYPE_CHECKING: | |
| from ssl import SSLContext | |
| from slack_sdk import WebClient | |
| from camel.toolkits import FunctionTool | |
| logger = logging.getLogger(__name__) | |
| class SlackToolkit(BaseToolkit): | |
| r"""A class representing a toolkit for Slack operations. | |
| This class provides methods for Slack operations such as creating a new | |
| channel, joining an existing channel, leaving a channel. | |
| """ | |
| def _login_slack( | |
| self, | |
| slack_token: Optional[str] = None, | |
| ssl: Optional[SSLContext] = None, | |
| ) -> WebClient: | |
| r"""Authenticate using the Slack API. | |
| Args: | |
| slack_token (str, optional): The Slack API token. | |
| If not provided, it attempts to retrieve the token from | |
| the environment variable SLACK_BOT_TOKEN or SLACK_USER_TOKEN. | |
| ssl (SSLContext, optional): SSL context for secure connections. | |
| Defaults to `None`. | |
| Returns: | |
| WebClient: A WebClient object for interacting with Slack API. | |
| Raises: | |
| ImportError: If slack_sdk package is not installed. | |
| KeyError: If SLACK_BOT_TOKEN or SLACK_USER_TOKEN | |
| environment variables are not set. | |
| """ | |
| try: | |
| from slack_sdk import WebClient | |
| except ImportError as e: | |
| raise ImportError( | |
| "Cannot import slack_sdk. Please install the package with \ | |
| `pip install slack_sdk`." | |
| ) from e | |
| if not slack_token: | |
| slack_token = os.environ.get("SLACK_BOT_TOKEN") or os.environ.get( | |
| "SLACK_USER_TOKEN" | |
| ) | |
| if not slack_token: | |
| raise KeyError( | |
| "SLACK_BOT_TOKEN or SLACK_USER_TOKEN environment " | |
| "variable not set." | |
| ) | |
| client = WebClient(token=slack_token, ssl=ssl) | |
| logger.info("Slack login successful.") | |
| return client | |
| def create_slack_channel( | |
| self, name: str, is_private: Optional[bool] = True | |
| ) -> str: | |
| r"""Creates a new slack channel, either public or private. | |
| Args: | |
| name (str): Name of the public or private channel to create. | |
| is_private (bool, optional): Whether to create a private channel | |
| instead of a public one. Defaults to `True`. | |
| Returns: | |
| str: JSON string containing information about Slack | |
| channel created. | |
| Raises: | |
| SlackApiError: If there is an error during get slack channel | |
| information. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| response = slack_client.conversations_create( | |
| name=name, is_private=is_private | |
| ) | |
| channel_id = response["channel"]["id"] | |
| response = slack_client.conversations_archive(channel=channel_id) | |
| return str(response) | |
| except SlackApiError as e: | |
| return f"Error creating conversation: {e.response['error']}" | |
| def join_slack_channel(self, channel_id: str) -> str: | |
| r"""Joins an existing Slack channel. | |
| Args: | |
| channel_id (str): The ID of the Slack channel to join. | |
| Returns: | |
| str: A confirmation message indicating whether join successfully | |
| or an error message. | |
| Raises: | |
| SlackApiError: If there is an error during get slack channel | |
| information. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| response = slack_client.conversations_join(channel=channel_id) | |
| return str(response) | |
| except SlackApiError as e: | |
| return f"Error creating conversation: {e.response['error']}" | |
| def leave_slack_channel(self, channel_id: str) -> str: | |
| r"""Leaves an existing Slack channel. | |
| Args: | |
| channel_id (str): The ID of the Slack channel to leave. | |
| Returns: | |
| str: A confirmation message indicating whether leave successfully | |
| or an error message. | |
| Raises: | |
| SlackApiError: If there is an error during get slack channel | |
| information. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| response = slack_client.conversations_leave(channel=channel_id) | |
| return str(response) | |
| except SlackApiError as e: | |
| return f"Error creating conversation: {e.response['error']}" | |
| def get_slack_channel_information(self) -> str: | |
| r"""Retrieve Slack channels and return relevant information in JSON | |
| format. | |
| Returns: | |
| str: JSON string containing information about Slack channels. | |
| Raises: | |
| SlackApiError: If there is an error during get slack channel | |
| information. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| response = slack_client.conversations_list() | |
| conversations = response["channels"] | |
| # Filtering conversations and extracting required information | |
| filtered_result = [ | |
| { | |
| key: conversation[key] | |
| for key in ("id", "name", "created", "num_members") | |
| } | |
| for conversation in conversations | |
| if all( | |
| key in conversation | |
| for key in ("id", "name", "created", "num_members") | |
| ) | |
| ] | |
| return json.dumps(filtered_result, ensure_ascii=False) | |
| except SlackApiError as e: | |
| return f"Error creating conversation: {e.response['error']}" | |
| def get_slack_channel_message(self, channel_id: str) -> str: | |
| r"""Retrieve messages from a Slack channel. | |
| Args: | |
| channel_id (str): The ID of the Slack channel to retrieve messages | |
| from. | |
| Returns: | |
| str: JSON string containing filtered message data. | |
| Raises: | |
| SlackApiError: If there is an error during get | |
| slack channel message. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| result = slack_client.conversations_history(channel=channel_id) | |
| messages = result["messages"] | |
| filtered_messages = [ | |
| {key: message[key] for key in ("user", "text", "ts")} | |
| for message in messages | |
| if all(key in message for key in ("user", "text", "ts")) | |
| ] | |
| return json.dumps(filtered_messages, ensure_ascii=False) | |
| except SlackApiError as e: | |
| return f"Error retrieving messages: {e.response['error']}" | |
| def send_slack_message( | |
| self, | |
| message: str, | |
| channel_id: str, | |
| user: Optional[str] = None, | |
| ) -> str: | |
| r"""Send a message to a Slack channel. | |
| Args: | |
| message (str): The message to send. | |
| channel_id (str): The ID of the Slack channel to send message. | |
| user (Optional[str]): The user ID of the recipient. | |
| Defaults to `None`. | |
| Returns: | |
| str: A confirmation message indicating whether the message was sent | |
| successfully or an error message. | |
| Raises: | |
| SlackApiError: If an error occurs while sending the message. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| if user: | |
| response = slack_client.chat_postEphemeral( | |
| channel=channel_id, text=message, user=user | |
| ) | |
| else: | |
| response = slack_client.chat_postMessage( | |
| channel=channel_id, text=message | |
| ) | |
| return str(response) | |
| except SlackApiError as e: | |
| return f"Error creating conversation: {e.response['error']}" | |
| def delete_slack_message( | |
| self, | |
| time_stamp: str, | |
| channel_id: str, | |
| ) -> str: | |
| r"""Delete a message to a Slack channel. | |
| Args: | |
| time_stamp (str): Timestamp of the message to be deleted. | |
| channel_id (str): The ID of the Slack channel to delete message. | |
| Returns: | |
| str: A confirmation message indicating whether the message | |
| was delete successfully or an error message. | |
| Raises: | |
| SlackApiError: If an error occurs while sending the message. | |
| """ | |
| from slack_sdk.errors import SlackApiError | |
| try: | |
| slack_client = self._login_slack() | |
| response = slack_client.chat_delete( | |
| channel=channel_id, ts=time_stamp | |
| ) | |
| return str(response) | |
| except SlackApiError as e: | |
| return f"Error creating conversation: {e.response['error']}" | |
| def get_tools(self) -> List[FunctionTool]: | |
| r"""Returns a list of FunctionTool objects representing the | |
| functions in the toolkit. | |
| Returns: | |
| List[FunctionTool]: A list of FunctionTool objects | |
| representing the functions in the toolkit. | |
| """ | |
| return [ | |
| FunctionTool(self.create_slack_channel), | |
| FunctionTool(self.join_slack_channel), | |
| FunctionTool(self.leave_slack_channel), | |
| FunctionTool(self.get_slack_channel_information), | |
| FunctionTool(self.get_slack_channel_message), | |
| FunctionTool(self.send_slack_message), | |
| FunctionTool(self.delete_slack_message), | |
| ] | |