Spaces:
Runtime error
Runtime error
Resolve user identifiers to display or real names for incoming Slack messages
Browse files
src/ctp_slack_bot/app.py
CHANGED
@@ -34,7 +34,7 @@ async def main() -> None:
|
|
34 |
container.schedule_service()
|
35 |
|
36 |
# Start the Slack socket mode handler in the background.
|
37 |
-
socket_mode_handler = container.socket_mode_handler()
|
38 |
slack_bolt_task = create_task(socket_mode_handler.start_async())
|
39 |
shutdown_signal_handler = create_shutdown_signal_handler()
|
40 |
loop = get_running_loop()
|
|
|
34 |
container.schedule_service()
|
35 |
|
36 |
# Start the Slack socket mode handler in the background.
|
37 |
+
socket_mode_handler = await container.socket_mode_handler()
|
38 |
slack_bolt_task = create_task(socket_mode_handler.start_async())
|
39 |
shutdown_signal_handler = create_shutdown_signal_handler()
|
40 |
loop = get_running_loop()
|
src/ctp_slack_bot/services/slack_service.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1 |
-
from dependency_injector.resources import
|
2 |
from loguru import logger
|
3 |
from openai import OpenAI
|
4 |
from pydantic import BaseModel
|
|
|
5 |
from slack_bolt.async_app import AsyncApp
|
|
|
6 |
from typing import Any, Mapping, Self
|
7 |
|
8 |
from ctp_slack_bot.enums import EventType
|
@@ -10,6 +12,9 @@ from ctp_slack_bot.models import SlackMessage, SlackResponse
|
|
10 |
from ctp_slack_bot.services.event_brokerage_service import EventBrokerageService
|
11 |
|
12 |
|
|
|
|
|
|
|
13 |
class SlackService(BaseModel):
|
14 |
"""
|
15 |
Service for interfacing with Slack.
|
@@ -17,6 +22,7 @@ class SlackService(BaseModel):
|
|
17 |
|
18 |
event_brokerage_service: EventBrokerageService
|
19 |
slack_bolt_app: AsyncApp
|
|
|
20 |
|
21 |
class Config:
|
22 |
arbitrary_types_allowed = True
|
@@ -28,6 +34,7 @@ class SlackService(BaseModel):
|
|
28 |
logger.debug("Created {}", self.__class__.__name__)
|
29 |
|
30 |
def adapt_event_payload(self: Self, event: Mapping[str, Any]) -> SlackMessage:
|
|
|
31 |
return SlackMessage(
|
32 |
type=event.get("type"),
|
33 |
subtype=event.get("subtype"),
|
@@ -36,7 +43,7 @@ class SlackService(BaseModel):
|
|
36 |
user=event.get("user"),
|
37 |
bot_id=event.get("bot_id"),
|
38 |
thread_ts=event.get("thread_ts"),
|
39 |
-
text=
|
40 |
ts=event.get("ts"),
|
41 |
event_ts=event.get("event_ts")
|
42 |
)
|
@@ -57,13 +64,23 @@ class SlackService(BaseModel):
|
|
57 |
logger.debug("Received app mention for processing: {}", body.get("event", {}).get("text"))
|
58 |
await self.process_message(body)
|
59 |
|
60 |
-
def
|
61 |
self.slack_bolt_app.event("message")(self.handle_message_event)
|
62 |
self.slack_bolt_app.event("app_mention")(self.handle_app_mention_event)
|
63 |
logger.debug("Registered 2 handlers for Slack Bolt message and app mention events.")
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
return slack_service
|
|
|
1 |
+
from dependency_injector.resources import AsyncResource
|
2 |
from loguru import logger
|
3 |
from openai import OpenAI
|
4 |
from pydantic import BaseModel
|
5 |
+
from re import compile as compile_re
|
6 |
from slack_bolt.async_app import AsyncApp
|
7 |
+
from slack_sdk.web.async_slack_response import AsyncSlackResponse
|
8 |
from typing import Any, Mapping, Self
|
9 |
|
10 |
from ctp_slack_bot.enums import EventType
|
|
|
12 |
from ctp_slack_bot.services.event_brokerage_service import EventBrokerageService
|
13 |
|
14 |
|
15 |
+
SLACK_USER_MENTION_PATTERN = compile_re(r"<@([A-Z0-9]+)>")
|
16 |
+
|
17 |
+
|
18 |
class SlackService(BaseModel):
|
19 |
"""
|
20 |
Service for interfacing with Slack.
|
|
|
22 |
|
23 |
event_brokerage_service: EventBrokerageService
|
24 |
slack_bolt_app: AsyncApp
|
25 |
+
user_id_name_map: dict[str, str] # This is deliberately mutable; the map may change as new users are encountered.
|
26 |
|
27 |
class Config:
|
28 |
arbitrary_types_allowed = True
|
|
|
34 |
logger.debug("Created {}", self.__class__.__name__)
|
35 |
|
36 |
def adapt_event_payload(self: Self, event: Mapping[str, Any]) -> SlackMessage:
|
37 |
+
text = SLACK_USER_MENTION_PATTERN.sub(lambda match: f"@{self.user_id_name_map.get(match.group(1))}", event.get("text", "")) # TODO: permit look-up of Slack again when not found.
|
38 |
return SlackMessage(
|
39 |
type=event.get("type"),
|
40 |
subtype=event.get("subtype"),
|
|
|
43 |
user=event.get("user"),
|
44 |
bot_id=event.get("bot_id"),
|
45 |
thread_ts=event.get("thread_ts"),
|
46 |
+
text=text,
|
47 |
ts=event.get("ts"),
|
48 |
event_ts=event.get("event_ts")
|
49 |
)
|
|
|
64 |
logger.debug("Received app mention for processing: {}", body.get("event", {}).get("text"))
|
65 |
await self.process_message(body)
|
66 |
|
67 |
+
def initialize(self: Self) -> None:
|
68 |
self.slack_bolt_app.event("message")(self.handle_message_event)
|
69 |
self.slack_bolt_app.event("app_mention")(self.handle_app_mention_event)
|
70 |
logger.debug("Registered 2 handlers for Slack Bolt message and app mention events.")
|
71 |
|
72 |
+
|
73 |
+
class SlackServiceResource(AsyncResource):
|
74 |
+
async def init(self: Self, event_brokerage_service: EventBrokerageService, slack_bolt_app: AsyncApp) -> SlackService:
|
75 |
+
match await slack_bolt_app.client.users_list():
|
76 |
+
case AsyncSlackResponse(status_code=200, data={"ok": True, "members": users}):
|
77 |
+
user_id_name_map = {user["id"]: user["profile"]["display_name"] or user["real_name"]
|
78 |
+
for user
|
79 |
+
in users}
|
80 |
+
logger.debug("Obtained a list of {} user name(s) for the workspace: {}", len(user_id_name_map), user_id_name_map)
|
81 |
+
case something:
|
82 |
+
user_id_name_map = {}
|
83 |
+
logger.error("Could not obtain a list of user name for the workspace.")
|
84 |
+
slack_service = SlackService(event_brokerage_service=event_brokerage_service, slack_bolt_app=slack_bolt_app, user_id_name_map=user_id_name_map)
|
85 |
+
slack_service.initialize()
|
86 |
return slack_service
|