Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stats bug prevention #407

Merged
merged 5 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions bots/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.db import models, transaction
from django.db.models import Q, IntegerChoices
from django.db.models import Q, IntegerChoices, QuerySet
from django.utils import timezone
from django.utils.text import Truncator
from phonenumber_field.modelfields import PhoneNumberField
Expand Down Expand Up @@ -875,16 +875,9 @@ class ConvoState(models.IntegerChoices):


class ConversationQuerySet(models.QuerySet):
def get_unique_users(self) -> models.QuerySet["Conversation"]:
def distinct_by_user_id(self) -> QuerySet["Conversation"]:
"""Get unique conversations"""
return self.distinct(
"fb_page_id",
"ig_account_id",
"wa_phone_number",
"slack_user_id",
"twilio_phone_number",
"web_user_id",
)
return self.distinct(*Conversation.user_id_fields)

def to_df(self, tz=pytz.timezone(settings.TIME_ZONE)) -> "pd.DataFrame":
import pandas as pd
Expand Down Expand Up @@ -1095,6 +1088,16 @@ class Conversation(models.Model):

objects = ConversationQuerySet.as_manager()

user_id_fields = [
"fb_page_id",
"ig_account_id",
"slack_user_id",
"web_user_id",
"wa_phone_number",
"twilio_phone_number",
"id",
]

class Meta:
unique_together = [
("slack_channel_id", "slack_user_id", "slack_team_id"),
Expand All @@ -1120,17 +1123,22 @@ def __str__(self):
def get_display_name(self):
return (
(self.wa_phone_number and self.wa_phone_number.as_international)
or (self.twilio_phone_number and self.twilio_phone_number.as_international)
or self.ig_username
or self.fb_page_name
or " in #".join(
filter(None, [self.slack_user_name, self.slack_channel_name])
)
or self.fb_page_id
or self.slack_user_id
or self.web_user_id
or (self.twilio_phone_number and self.twilio_phone_number.as_international)
or self.unique_user_id()
)

def unique_user_id(self) -> str | None:
for col in self.user_id_fields:
if col == "id":
return self.api_integration_id()
if value := getattr(self, col, None):
return value

get_display_name.short_description = "User"

def last_active_delta(self) -> datetime.timedelta:
Expand Down Expand Up @@ -1166,6 +1174,10 @@ def api_integration_id(self) -> str:


class MessageQuerySet(models.QuerySet):
def distinct_by_user_id(self) -> QuerySet["Message"]:
"""Get unique users"""
return self.distinct(*Message.convo_user_id_fields)

def to_df(self, tz=pytz.timezone(settings.TIME_ZONE)) -> "pd.DataFrame":
import pandas as pd

Expand Down Expand Up @@ -1381,6 +1393,10 @@ class Message(models.Model):

objects = MessageQuerySet.as_manager()

convo_user_id_fields = [
f"conversation__{col}" for col in Conversation.user_id_fields
]

class Meta:
ordering = ("-created_at",)
get_latest_by = "created_at"
Expand Down
30 changes: 9 additions & 21 deletions recipes/VideoBotsStats.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,6 @@
from gooey_ui import RedirectException
from recipes.VideoBots import VideoBotsPage

ID_COLUMNS = [
"conversation__fb_page_id",
"conversation__ig_account_id",
"conversation__wa_phone_number",
"conversation__slack_user_id",
"conversation__twilio_phone_number",
"conversation__web_user_id",
]


class VideoBotsStatsPage(BasePage):
title = "Copilot Analytics" # "Create Interactive Video Bots"
Expand Down Expand Up @@ -411,7 +402,7 @@ def calculate_overall_stats(*, bi, run_title, run_url):
bot_integration=bi
).order_by() # type: ignore
# due to things like personal convos for slack, each user can have multiple conversations
users = conversations.get_unique_users().order_by()
users = conversations.distinct_by_user_id().order_by()
messages: MessageQuerySet = Message.objects.filter(conversation__in=conversations).order_by() # type: ignore
user_messages = messages.filter(role=CHATML_ROLE_USER).order_by()
bot_messages = messages.filter(role=CHATML_ROLE_ASSISTANT).order_by()
Expand All @@ -420,19 +411,15 @@ def calculate_overall_stats(*, bi, run_title, run_url):
conversation__in=users,
created_at__gte=timezone.now() - timedelta(days=7),
)
.distinct(
*ID_COLUMNS,
)
.distinct_by_user_id()
.count()
)
num_active_users_last_30_days = (
user_messages.filter(
conversation__in=users,
created_at__gte=timezone.now() - timedelta(days=30),
)
.distinct(
*ID_COLUMNS,
)
.distinct_by_user_id()
.count()
)
positive_feedbacks = Feedback.objects.filter(
Expand All @@ -444,14 +431,17 @@ def calculate_overall_stats(*, bi, run_title, run_url):
rating=Feedback.Rating.RATING_THUMBS_DOWN,
).count()
run_link = f'Powered By: <a href="{run_url}" target="_blank">{run_title}</a>'
connection_detail = bi.get_display_name()
if bi.get_display_name() != bi.name:
connection_detail = f"- Connected to: {bi.get_display_name()}"
else:
connection_detail = ""
st.markdown(
f"""
- Platform: {Platform(bi.platform).name.capitalize()}
- Created on: {bi.created_at.strftime("%b %d, %Y")}
- Last Updated: {bi.updated_at.strftime("%b %d, %Y")}
- {run_link}
- Connected to: {connection_detail}
{connection_detail}
* {users.count()} Users
* {num_active_users_last_7_days} Active Users (Last 7 Days)
* {num_active_users_last_30_days} Active Users (Last 30 Days)
Expand Down Expand Up @@ -485,9 +475,7 @@ def calculate_stats_binned_by_time(*, bi, start_date, end_date, factor, trunc_fn
.annotate(Convos=Count("conversation_id", distinct=True))
.annotate(
Senders=Count(
Concat(
*ID_COLUMNS,
),
Concat(*Message.convo_user_id_fields),
distinct=True,
)
)
Expand Down