diff --git a/bots/models.py b/bots/models.py index 9073a0f13..2fd06f5aa 100644 --- a/bots/models.py +++ b/bots/models.py @@ -875,9 +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(*Conversation.ID_COLUMNS) + return self.distinct(*Conversation.user_id_fields) def to_df(self, tz=pytz.timezone(settings.TIME_ZONE)) -> "pd.DataFrame": import pandas as pd @@ -1088,7 +1088,7 @@ class Conversation(models.Model): objects = ConversationQuerySet.as_manager() - ID_COLUMNS = [ + user_id_fields = [ "fb_page_id", "ig_account_id", "slack_user_id", @@ -1119,14 +1119,6 @@ class Meta: def __str__(self): return f"{self.get_display_name()} <> {self.bot_integration}" - def get_id(self): - self_id = None - for col in self.ID_COLUMNS: - if getattr(self, col): - self_id = getattr(self, col) - break - return self_id - def get_display_name(self): return ( (self.wa_phone_number and self.wa_phone_number.as_international) @@ -1136,9 +1128,14 @@ def get_display_name(self): or " in #".join( filter(None, [self.slack_user_name, self.slack_channel_name]) ) - or self.get_id() + or self.unique_user_id() ) + def unique_user_id(self) -> str | None: + for col in self.user_id_fields: + if value := getattr(self, col, None): + return value + get_display_name.short_description = "User" def last_active_delta(self) -> datetime.timedelta: @@ -1174,9 +1171,9 @@ def api_integration_id(self) -> str: class MessageQuerySet(models.QuerySet): - def get_unique_users(self) -> QuerySet["Message"]: + def distinct_by_user_id(self) -> QuerySet["Message"]: """Get unique users""" - return self.distinct(*Message.CONVO_ID_COLUMNS) + return self.distinct(*Message.convo_user_id_fields) def to_df(self, tz=pytz.timezone(settings.TIME_ZONE)) -> "pd.DataFrame": import pandas as pd @@ -1393,7 +1390,9 @@ class Message(models.Model): objects = MessageQuerySet.as_manager() - CONVO_ID_COLUMNS = [f"conversation__{col}" for col in Conversation.ID_COLUMNS] + convo_user_id_fields = [ + f"conversation__{col}" for col in Conversation.user_id_fields + ] class Meta: ordering = ("-created_at",) diff --git a/recipes/VideoBotsStats.py b/recipes/VideoBotsStats.py index 7cf47659d..36a8401b8 100644 --- a/recipes/VideoBotsStats.py +++ b/recipes/VideoBotsStats.py @@ -402,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() @@ -411,7 +411,7 @@ def calculate_overall_stats(*, bi, run_title, run_url): conversation__in=users, created_at__gte=timezone.now() - timedelta(days=7), ) - .get_unique_users() + .distinct_by_user_id() .count() ) num_active_users_last_30_days = ( @@ -419,7 +419,7 @@ def calculate_overall_stats(*, bi, run_title, run_url): conversation__in=users, created_at__gte=timezone.now() - timedelta(days=30), ) - .get_unique_users() + .distinct_by_user_id() .count() ) positive_feedbacks = Feedback.objects.filter( @@ -431,11 +431,10 @@ def calculate_overall_stats(*, bi, run_title, run_url): rating=Feedback.Rating.RATING_THUMBS_DOWN, ).count() run_link = f'Powered By: {run_title}' - connection_detail = ( - f"- Connected to: {bi.get_display_name()}" - if bi.get_display_name() != bi.name - else "" - ) + 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()} @@ -476,7 +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(*Message.CONVO_ID_COLUMNS), + Concat(*Message.convo_user_id_fields), distinct=True, ) )