Skip to content

Commit 4399267

Browse files
committed
Add discord bot for handling different event types
1 parent f51d3ed commit 4399267

File tree

6 files changed

+90
-19
lines changed

6 files changed

+90
-19
lines changed

backend/app/core/events/base.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ class BaseEvent(BaseModel):
88
platform: str
99
event_type: str
1010
timestamp: datetime = Field(default_factory=datetime.now, description="Timestamp of the event")
11+
channel_id: str | None = None
1112
actor_id: str = Field(..., description="ID of the user who triggered the event")
1213
actor_name: Optional[str] = Field(None, description="Name of the user who triggered the event")
1314
raw_data: Dict[str, Any] = Field({}, description="Raw event data from the platform")
1415
metadata: Dict[str, Any] = Field({}, description="Additional metadata for the event")
15-
16+
content: Optional[str] = Field(None, description="Content of the event")
17+
1618
def to_dict(self) -> Dict[str, Any]:
1719
"""Convert event to dictionary for serialization"""
1820
return self.model_dump()
19-
21+
2022
@classmethod
2123
def from_dict(cls, data: Dict[str, Any]) -> "BaseEvent":
2224
"""Create event from dictionary"""
23-
return cls(**data)
25+
return cls(**data)

backend/app/core/events/discord_event.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,27 @@
66
class DiscordEvent(BaseEvent):
77
"""Discord specific event model"""
88
platform: PlatformType = PlatformType.DISCORD
9-
guild_id: str
10-
channel_id: str
9+
guild_id: Optional[str] = None
10+
channel_id: Optional[str] = None
1111
message_id: Optional[str] = None
1212
content: Optional[str] = None
1313
attachments: List[Dict[str, Any]] = Field(default_factory=list)
1414
mentions: List[str] = Field(default_factory=list)
1515

1616
def __init__(self, **data):
1717
"""Ensure event data is properly initialized from raw_data"""
18-
super().__init__(**data)
19-
2018
raw_data = data.get("raw_data", {})
2119

22-
self.content = raw_data.get("content") or self.content
23-
self.message_id = raw_data.get("id") or self.message_id
24-
self.attachments = raw_data.get("attachments", []) or self.attachments
25-
self.mentions = raw_data.get("mentions", []) or self.mentions
20+
super().__init__(
21+
id=data.get("id"),
22+
event_type=data.get("event_type"),
23+
platform=PlatformType.DISCORD,
24+
actor_id=data.get("actor_id") or raw_data.get("actor_id"),
25+
actor_name=data.get("actor_name"),
26+
raw_data=raw_data,
27+
metadata=data.get("metadata", {}),
28+
guild_id=raw_data.get("guild_id"),
29+
message_id=raw_data.get("id"),
30+
content=raw_data.get("content"),
31+
channel_id=data.get("channel_id"),
32+
)

backend/app/core/events/event_bus.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ def register_handler(self, event_type: Union[EventType, List[EventType]], handle
2222
self._add_handler(et, handler_func)
2323
else:
2424
self._add_handler(event_type, handler_func)
25-
logger.info(f"Handler {handler_func.__name__} registered for event type {event_type}")
2625
pass
2726

2827
def _add_handler(self, event_type: EventType, handler_func: callable):
@@ -35,13 +34,10 @@ def _add_handler(self, event_type: EventType, handler_func: callable):
3534
def register_global_handler(self, handler_func):
3635
"""Register a handler that will receive all events"""
3736
self.global_handlers.append(handler_func)
38-
logger.info(f"Global handler {handler_func._name_} registered")
3937
pass
4038

4139
async def dispatch(self, event: BaseEvent):
4240
"""Dispatch an event to all registered handlers"""
43-
logger.info(f"Dispatching event {event.id} of type {event.event_type}")
44-
logger.info("event in event bus" + str(event))
4541

4642
# Call global handlers first
4743
for handler in self.global_handlers:
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import logging
2+
from typing import Dict, Any
3+
from app.core.events.base import BaseEvent
4+
from app.core.events.enums import EventType, PlatformType
5+
from app.core.handler.base import BaseHandler
6+
7+
logger = logging.getLogger(__name__)
8+
9+
class FAQHandler(BaseHandler):
10+
"""Handler for FAQ and knowledge base queries"""
11+
12+
def __init__(self, bot=None):
13+
self.bot = bot
14+
self.faq_responses = {
15+
"what is devr.ai?": "Devr.AI is an AI-powered Developer Relations assistant that helps open-source communities by automating engagement and issue tracking.",
16+
"how do i contribute?": "You can contribute by visiting our GitHub repo, checking open issues, and submitting pull requests.",
17+
"what platforms does devr.ai support?": "Devr.AI integrates with Discord, Slack, GitHub, and Discourse to assist developers and maintainers.",
18+
"who maintains devr.ai?": "Devr.AI is maintained by an open-source community of developers.",
19+
"how do i report a bug?": "You can report a bug by opening an issue on our GitHub repository.",
20+
}
21+
22+
async def is_faq(self, message: str):
23+
"""Check if the question is in the FAQ and return the response"""
24+
for key in self.faq_responses:
25+
if message.lower() == key.lower():
26+
return True, self.faq_responses[key]
27+
return False, None
28+
29+
async def handle(self, event: BaseEvent) -> Dict[str, Any]:
30+
logger.info(f"Handling FAQ request event: {event.event_type}")
31+
32+
if event.event_type == EventType.FAQ_REQUESTED:
33+
return await self._handle_faq_request(event)
34+
elif event.event_type == EventType.KNOWLEDGE_UPDATED:
35+
return await self._handle_knowledge_update(event)
36+
else:
37+
logger.warning(f"Unsupported FAQ event type: {event.event_type}")
38+
return {"success": False, "reason": "Unsupported event type"}
39+
40+
async def _handle_faq_request(self, event: BaseEvent) -> Dict[str, Any]:
41+
question = (event.content or "").strip().lower()
42+
response = self.get_faq_response(question)
43+
44+
logger.info("Question: " + question + ", Response: " + response)
45+
46+
await self._send_discord_response(event.channel_id, response)
47+
return {"success": True, "action": "faq_response_sent"}
48+
49+
def get_faq_response(self, question: str) -> str:
50+
return self.faq_responses.get(question.lower(), "I'm not sure about that, but I can find out!")
51+
52+
async def _handle_knowledge_update(self, event: BaseEvent) -> Dict[str, Any]:
53+
"""Handles knowledge base updates."""
54+
return {"success": True, "action": "knowledge_updated"}
55+
56+
async def _send_discord_response(self, channel_id: str, response: str):
57+
"""Sends a response message to the specified Discord channel."""
58+
if self.bot:
59+
channel = self.bot.get_channel(int(channel_id))
60+
if channel:
61+
await channel.send(response)
62+
else:
63+
logger.error(f"Could not find Discord channel with ID {channel_id}")

backend/app/core/handler/message_handler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ def __init__(self, bot=None):
1515

1616
async def handle(self, event: BaseEvent) -> Dict[str, Any]:
1717
logger.info(f"Handling message event from {event.platform}: {event.event_type}")
18-
1918
if event.event_type == EventType.MESSAGE_CREATED:
2019
return await self._handle_message_created(event)
2120
elif event.event_type == EventType.MESSAGE_UPDATED:
@@ -35,10 +34,11 @@ async def _handle_message_created(self, event: BaseEvent) -> Dict[str, Any]:
3534
# Check if it's a FAQ request
3635
if await self.faq_handler.is_faq(user_message):
3736
faq_event = BaseEvent(
37+
id=event.id,
3838
event_type=EventType.FAQ_REQUESTED,
3939
platform=event.platform,
40-
channel_id=event.channel_id,
41-
user_id=event.user_id,
40+
channel_id=event.raw_data.get("channel_id"),
41+
actor_id=event.actor_id,
4242
data={"content": user_message},
4343
)
4444
return await self.faq_handler.handle(faq_event)

backend/bots/discord_bot/discordBot.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ async def on_message(message):
8484
return
8585

8686
logger.info(f"Message received: {message.content} from {message.author.name}")
87+
logger.info(f"Dispatching event with channel_id: {str(message.channel.id)}")
88+
channel_id = str(message.channel.id)
8789

8890
is_faq, faq_response = await faq_handler.is_faq(message.content)
8991
event_type = EventType.FAQ_REQUESTED if is_faq else EventType.MESSAGE_CREATED
@@ -95,11 +97,12 @@ async def on_message(message):
9597
actor_id=str(message.author.id),
9698
actor_name=message.author.name,
9799
guild_id=str(message.guild.id) if message.guild else None,
98-
channel_id=str(message.channel.id),
100+
channel_id=(channel_id),
99101
message_id=str(message.id),
100102
raw_data={
101103
"id": str(message.id),
102104
"content": message.content,
105+
"actor_id": str(message.author.id),
103106
"attachments": [attachment.url for attachment in message.attachments],
104107
"mentions": [user.id for user in message.mentions],
105108
},

0 commit comments

Comments
 (0)