Source code for src.commands.check_vibes_command

# src/commands/check_vibes_command.py
import logging
import json
import threading
import os
from datetime import datetime
from datetime import date, timedelta
from urllib.parse import urlencode

from pymongo import MongoClient
from services.prompt_service import get_random_prompt_text, mark_prompt_asked
from services.mongo_service import get_tracker

[docs] def databse_Task(mongo_client, payload, respond, botID, client, dayValue, specificVibe): try: db = mongo_client.get_database("vibecheck") except Exception as e: print(f"[CHECK VIBES COMMAND] Failed to get the vibe check database: {e}") try: installations_col = db.get_collection("installations") except Exception as e: print(f"[CHECK VIBES COMMAND] Failed to get the installations collection: {e}") channel = payload.get("channel_id") # default to the channel where command was used team_id = ( payload.get("team_id") or (payload.get("authorizations") or [{}])[0].get("team_id") or None ) team_name = None if team_id: record = installations_col.find_one({"team_id": team_id}) if record: team_name = record.get("team_name") collection_name = f"messages_{team_name}" if team_name else f"messages_{team_id or 'unknown'}" try: messages_col = db[collection_name] # db.get_collection(collection_name) print(collection_name) except Exception as e: print(f"[CHECK VIBES COMMAND] Failed to get the message collection: {e}") try: message_array = list(messages_col.find({})) prompt_list = organize_data(message_array, botID) except Exception as e: print(f"[CHECK VIBES COMMAND] Failed to create the message array: {e}") CurrentDaysVibes = [] curDate = dayValue if dayValue: for vibe in prompt_list: vibeDT = datetime.fromisoformat(vibe["time"]).astimezone() if (vibeDT.day == curDate.day and vibeDT.month == curDate.month and vibeDT.year == curDate.year): CurrentDaysVibes.append(vibe) if len(CurrentDaysVibes) == 0 and dayValue: respond(f"No Vibes Checks have been sent that day... :( | Day Value: {dayValue}, Amount of Current Days: {len(CurrentDaysVibes)}") return msg_block = [] headerText = "VIBES FOR TODAY" dateInfo = f"({curDate})" if not dayValue: headerText = "VIBES FOR CHANNEL" CurrentDaysVibes = prompt_list dateInfo = f"" else: if ((datetime.today() - timedelta(days=1)) == curDate): headerText = "VIBES FOR YESTERDAY" else: headerText = "VIBES FOR THE DAY OF" msg_block.append({ "type": "header", "text": { "type": "plain_text", "text": f"{headerText} {dateInfo}", "emoji": True }, "level": 1 } ) if not specificVibe: msg_block.append({ "type": "header", "text": { "type": "plain_text", "text": f"VIBES SENT SO FAR: {len(CurrentDaysVibes)}", "emoji": True }, "level": 4 } ) msg_block.append( { "type": "markdown", "text": f"## KEY: VIBES\n do /checkvibes [(today) or (yesterday) or (all) or (mm-dd-yyyy)] #[Number Vibe you wish to see more information on]" }, ) forcedVibes = 0 userCreatedVibes = 0 randomVibes = 0 curVibeID = 0 chartLabels = [] chartEngagementData = [] chartRepliesData = [] chartUniqueUsersData = [] vibeLines = [] vibeInstanceSpecific = None for vibe in CurrentDaysVibes: if vibe["checkType"] == "forced": forcedVibes += 1 elif vibe["checkType"] == "random": randomVibes += 1 elif vibe["checkType"] == "user-created": userCreatedVibes += 1 curVibeID += 1 if specificVibe: _,_,results = specificVibe.partition("#") try: searchVibeID = int(results) if searchVibeID: if curVibeID == searchVibeID: vibeInstanceSpecific = vibe respond("Specific Vibe Found") except ValueError: respond("Vibe ID search invalid. Sending The Total Vibes.") vibeText = vibe["text"] vibeTime = vibe["time"] vibeReplies = len(vibe["replies"]) vibeUniqueUsers = len(vibe["unique_users"]) vibeEngagement = vibe["engagement"] if not vibeInstanceSpecific: chartLabels.append(f"Vibe #{curVibeID}") chartEngagementData.append(vibeEngagement) chartRepliesData.append(vibeReplies) chartUniqueUsersData.append(vibeUniqueUsers) _, _, vibeTextInitialSplit = vibeText.partition(">") vibePrompt, vibeMatch, vibeType = vibeTextInitialSplit.partition("```") vibeLines.append(f"\nVibe #{curVibeID}\n{vibePrompt}\n{vibeMatch}{vibeType}\n") # CANNOT DO THE MESSAGE BLOCK KEYS, BECAUSE THERE IS A LIMIT TO HOW MANY MESSAGE BLOCKS THERE CAN BE AND HOW LOGN THE MESSAGE BLOCKS CAN BE. if not vibeInstanceSpecific: chartEngagementConfig = { "type": "bar", "data": { "labels": chartLabels, "datasets": [{ "label": "Engagement Points", "data": chartEngagementData }] } } chartEngagementParams = { 'chart' : json.dumps(chartEngagementConfig), 'width' : 1200, 'height' : 400, 'backgroundColor': 'white', } msg_block.append( { "type": "image", "image_url": 'https://quickchart.io/chart?%s' % urlencode(chartEngagementParams), "alt_text": "Engagement Chart, based on how fast users reply and the qualities of the replies." } ) chartRepliesConfig = { "type": "bar", "data": { "labels": chartLabels, "datasets": [{ "label": "Replies", "data": chartRepliesData }] } } chartRepliesParams = { 'chart' : json.dumps(chartRepliesConfig), 'width' : 1200, 'height' : 400, 'backgroundColor': 'white', } msg_block.append( { "type": "image", "image_url": 'https://quickchart.io/chart?%s' % urlencode(chartRepliesParams), "alt_text": "Replies Chart, based on how many users replied." } ) chartUniqueUsersConfig = { "type": "bar", "data": { "labels": chartLabels, "datasets": [{ "label": "Unique Users", "data": chartUniqueUsersData }] } } chartUniqueUsersParams = { 'chart' : json.dumps(chartUniqueUsersConfig), 'width' : 1200, 'height' : 400, 'backgroundColor': 'white', } msg_block.append( { "type": "image", "image_url": 'https://quickchart.io/chart?%s' % urlencode(chartUniqueUsersParams), "alt_text": "Unique Users Chart, based on how many unique users replied." } ) # lines.append(f"\nVibe Prompt: {vibeText}\n • Time Released {vibeTime}\n • Replies: {vibeReplies}\n • # of Unique Repliers: {vibeUniqueUsers} \n • Vibe Total Engagement: {vibeEngagement}") msg_block.append({ "type": "section", "fields": [ { "type": "mrkdwn", "text": f"*Random Vibes:*\n{randomVibes}" }, { "type": "mrkdwn", "text": f"*Forced Vibes:*\n{forcedVibes}" }, { "type": "mrkdwn", "text": f"*User-created Vibes:*\n{userCreatedVibes}" } ] } ) else: msg_block.append({ "type": "header", "text": { "type": "plain_text", "text": f"SPECIFIC VIBE {specificVibe}", "emoji": True }, "level": 4 } ) _, _, vibeTextInitialSplit = vibeText.partition(">") vibePrompt, vibeMatch, vibeType = vibeTextInitialSplit.partition("```") msg_block.append({ "type": "markdown", "text": f"\n## Vibe Prompt:\n{vibePrompt}\n{vibeMatch}{vibeType}\n", } ) msg_block.append({ "type": "divider" } ) localTime = datetime.fromisoformat(vibeTime).astimezone() avgResponseTime = 0 chartVibeData = [] chartVibeLabels = [] vibeReplyID = 0 for reply in vibe["replies"]: avgResponseTime += reply.get("timeBetweenVibe") chartVibeData.append(reply.get("timeBetweenVibe")) vibeReplyID += 1 chartVibeLabels.append(f"Reply #{vibeReplyID}") avgResponseTime = (avgResponseTime / vibeReplies) msg_block.append({ "type": "markdown", "text": f"\n### Vibe Information:\n • Time Sent: {localTime.strftime("%I:%M:%S %p")} {localTime.tzinfo}\n • Unique Users: {vibeUniqueUsers}\n • Replies: {vibeReplies}\n • Average Time To Reply: {avgResponseTime} seconds\n • Engagement Score: {vibeEngagement}", } ) chartVibeConfig = { "type": "bar", "data": { "labels": chartVibeLabels, "datasets": [{ "label": "Response Time (seconds)", "data": chartVibeData }] } } chartVibeParams = { 'chart' : json.dumps(chartVibeConfig), 'width' : 1200, 'height' : 400, 'backgroundColor': 'white', } msg_block.append( { "type": "image", "image_url": 'https://quickchart.io/chart?%s' % urlencode(chartVibeParams), "alt_text": "Response Time Chart, how fast do users respond." } ) # TIME IT WAS SENT, #OF UNIQUE USERS, #OF REPLIES, AVERAGE TIME TO RESPOND, GRAPH TO SHOW THE TIME TO RESPOND. # lines.append(f"\nRandom Vibes: {randomVibes}\nForced Vibes: {forcedVibes}\nUser-Created Vibes: {userCreatedVibes}\n") # respond("\n".join(lines)) client.chat_postMessage(channel=channel, blocks=msg_block, text="Check Vibes Information")
# for message in message_array : # print(f"Message:{message.get("text")}")
[docs] def register_check_vibes_command(bolt_app, state_manager): mongo_client = MongoClient(os.getenv("MONGO_URI")) # BOT_USERID = @bolt_app.command("/checkvibes") def handle_checkvibes(ack, respond, body, client): ack("Checking out the vibes...") botID = client.auth_test()["user_id"] user_input = (body.get("text") or "").strip() parts = user_input.split() # Parse args in any order: # - "text" or "image" # - "#channel" dayVal = date.today() specific_vibe = None for p in parts: pl = p.lower() if pl in ("today", "yesterday", "all"): if pl == "all": dayVal = None elif pl == "yesterday": dayVal = (date.today() - timedelta(days=1)) elif pl.startswith("#"): specific_vibe = pl else: try: dayVal = datetime.strptime(pl, "%m-%d-%Y").date() except ValueError: respond("Attempted to process date entered: Month or Day is out of range. Ending process.") break except: respond("Error has occured while processing date.") break threading.Thread(target=databse_Task, args=(mongo_client, body, respond, botID, client, dayVal, specific_vibe)).start() # respond("Checking out the Vibes!!") # for message in messages_col.find(): # message.get() @bolt_app.action("checkvibes_moreInfo") def handle_action_more_info(ack, body, action, logger): ack() action_value = action.get("value") user_id = body["user"]["id"] channel_id = body["channel"]["id"] print(f"Clicked Button: {action_value}")
[docs] def organize_data(db, bot_id): vibe_prompt_list = [] MaxVibeID = 0 LatestVibeInstance = None for record in db: isoString = record.get("ingested_at_utc") if not record.get("user_id"): continue if (record.get("user_id") == bot_id): check_type = None if "VIBES SENT SO FAR" not in record.get("text") and "SPECIFIC VIBE" not in record.get("text") and "Check Vibes Information" not in record.get("text"): if "forced vibe check" in record.get("text"): check_type = "forced" elif "random vibe check" in record.get("text"): check_type = "random" elif "user-created vibe check" in record.get("text"): check_type = "user-created" if check_type: vibe_prompt_list.append({ "time" : isoString, "text" : record.get("text"), "thread": record.get("ts"), "channel": record.get("channel_id"), "vibeID" : (MaxVibeID := MaxVibeID + 1), "checkType": check_type, "replies" : [], "unique_users": [], "engagement" : 0 }) LatestVibeInstance = vibe_prompt_list[len(vibe_prompt_list) - 1] else: VibeInstance = None Replied = False if not record.get("thread_ts"): # THE MESSAGE SENT DOES NOT REPLY TO A THREAD, THEREFORE IT WILL USE THE LATEST VIBE INSTANCE. if LatestVibeInstance: # THERE IS A LATEST VIBE INSTACE, THEREFORE IT WILL ADD ITSELF TO THE REPLIES OF THE CHECK. # SHOULD CONTINUE ONWARDS THOUGH AND NOT RECORD REPLY IF THE MESSAGES ARE NOT IN THE CHANNEL AS THE PROMPT. VibeInstance = LatestVibeInstance else: # LOOP THROUGH THE AVAILBLE VIBE PROMPTS, COMPARE THE THREAD_TS of the record to the thread value. RepliedVibeInstance = None for vibe in vibe_prompt_list: if vibe["thread"] == record.get("thread_ts"): RepliedVibeInstance = vibe Replied = True break # IF THERE IS A MATCH, THEN ADD MESSAGE TO REPLY AND CANCEL. if RepliedVibeInstance: VibeInstance = RepliedVibeInstance if VibeInstance: if VibeInstance["channel"] != record.get("channel_id"): continue engageVal = 0 dt = datetime.fromisoformat(isoString) TimeOfVibe = datetime.fromisoformat(VibeInstance["time"]) secondsBetweenMessages = (dt - TimeOfVibe).total_seconds() if record.get("text") != "": engageVal += 10 if record.get("subtype"): if record.get("subtype") == "file_share": engageVal += 50 if Replied == True: engageVal += 5 if secondsBetweenMessages <= 300: engageVal *= 5 elif secondsBetweenMessages > 300 and secondsBetweenMessages <= 480: engageVal *= 4 elif secondsBetweenMessages > 300 and secondsBetweenMessages <= 480: engageVal *= 3 elif secondsBetweenMessages > 480 and secondsBetweenMessages <= 600: engageVal *= 2 elif secondsBetweenMessages > 600 and secondsBetweenMessages <= 1800: engageVal *= 1 else: engageVal *= 0 if secondsBetweenMessages > 1800 and (dt.month != TimeOfVibe.month or dt.year != TimeOfVibe.year or dt.day != TimeOfVibe.day) and Replied == False: # IF THE MESSAGE IS MORE THAN 30 MINUTES FROM THE VIBE INSTANCE # IF THE MESSAGE IS NOT THE SAME MONTH, DAY, OR YEAR # AND THis not a replied message, we will not add this one to the replies. # MESSAGE IS TOO OLD continue VibeInstance["replies"].append({ "time" : isoString, "timeBetweenVibe": secondsBetweenMessages, "text" : record.get("text"), "subtype" : record.get("subtype"), "engagementValue" : engageVal }) if record.get("user_id") not in VibeInstance["unique_users"]: VibeInstance["unique_users"].append(record.get("user_id")) VibeInstance["engagement"] += engageVal return vibe_prompt_list