Skip to content

Commit

Permalink
add ux for analytics tab & queries for calculating credit usage / run…
Browse files Browse the repository at this point in the history
… count
  • Loading branch information
nikochiko committed Dec 6, 2024
1 parent c7cbb66 commit e7bc3b4
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
1 change: 1 addition & 0 deletions daras_ai_v2/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
member = '<i class="fa-solid fa-user"></i>'
chevron_right = '<i class="fa-sharp-duotone fa-solid fa-sm fa-chevron-right"></i>'
check = '<i class="fa-solid fa-check"></i>'
analytics = '<i class="fa-regular fa-chart-pie"></i>'

# brands
github = '<i class="fa-brands fa-github"></i>'
Expand Down
64 changes: 64 additions & 0 deletions routers/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ def account_route(request: Request):
)


@gui.route(app, "/account/analytics")
def analytics_route(request: Request):
with account_page_wrapper(request, AccountTabs.analytics) as current_workspace:
analytics_tab(request)


@gui.route(app, "/account/profile/")
def profile_route(request: Request):
with account_page_wrapper(request, AccountTabs.profile) as current_workspace:
Expand Down Expand Up @@ -227,6 +233,7 @@ class AccountTabs(TabData, Enum):
saved = TabData(title=f"{icons.save} Saved", route=saved_route)
api_keys = TabData(title=f"{icons.api} API Keys", route=api_keys_route)
billing = TabData(title=f"{icons.billing} Billing", route=account_route)
analytics = TabData(title=f"{icons.analytics} Analytics", route=analytics_route)

@property
def url_path(self) -> str:
Expand All @@ -241,10 +248,12 @@ def get_tabs_for_user(

if workspace.is_personal:
ret.remove(cls.members)
ret.remove(cls.analytics)
else:
ret.remove(cls.profile)
if not workspace.memberships.get(user=user).can_edit_workspace():
ret.remove(cls.billing)
ret.remove(cls.analytics)

return ret

Expand Down Expand Up @@ -345,6 +354,61 @@ def _render_run(pr: PublishedRun):
paginate_button(url=request.url, cursor=cursor)


def analytics_tab(request: Request):
workspace = get_current_workspace(request.user, request.session)
gui.write("# Usage & Limits")
gui.caption(
f"Member, API & Integration usage for **{workspace.display_name(request.user)}**."
)

with gui.div(className="table-responsive"), gui.tag("table", className="table"):
with gui.tag("thead"), gui.tag("tr"):
with gui.tag("th", scope="col"):
gui.html("Name")
with gui.tag("th", scope="col"):
gui.html("Type")
with gui.tag("th", scope="col"):
gui.html("Runs")
with gui.tag("th", scope="col"):
gui.html("Credits Used")
with gui.tag("th", scope="col"):
gui.html("")

with gui.tag("tbody"):
for m in workspace.memberships.all():
with gui.tag("tr", className="no-margin"):
with gui.tag("td"):
gui.write(m.user.full_name())
with gui.tag("td"):
gui.html("User")
with gui.tag("td"):
gui.html(f"{m.get_run_count()}")
with gui.tag("td"):
gui.html(f"{m.get_credit_usage()} Cr")
with gui.tag("td"):
gui.html("")

with gui.tag("tr", className="no-margin"):
with gui.tag("td"):
gui.write(f"[API Keys]({get_route_path(api_keys_route)})")
with gui.tag("td"):
gui.html("API Key")
with gui.tag("td"):
gui.html(f"{workspace.get_api_key_run_count()}")
with gui.tag("td"):
gui.html(f"{workspace.get_api_key_credit_usage()} Cr")

with gui.tag("tr", className="no-margin"):
with gui.tag("td"):
gui.write("Bot Integrations")
with gui.tag("td"):
gui.html("Bot")
with gui.tag("td"):
gui.html(f"{workspace.get_bot_run_count()}")
with gui.tag("td"):
gui.html(f"{workspace.get_bot_credit_usage()} Cr")


def api_keys_tab(request: Request):
gui.write("# 🔐 API Keys")
workspace = get_current_workspace(request.user, request.session)
Expand Down
45 changes: 45 additions & 0 deletions workspaces/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.db import models, transaction, IntegrityError
from django.db.backends.base.schema import logger
from django.db.models.aggregates import Sum
from django.db.models.functions import Abs
from django.db.models.query_utils import Q
from django.utils import timezone
from django.utils.text import slugify
Expand Down Expand Up @@ -256,6 +257,35 @@ def add_balance(
pass
raise

def get_api_key_run_count(self) -> int:
return (
self.saved_runs.filter(is_api_call=True, price__gt=0)
.exclude(messages__isnull=False)
.count()
)

def get_api_key_credit_usage(self) -> int:
return (
self.saved_runs.filter(is_api_call=True)
.exclude(messages__isnull=False) # exclude bot-integration runs
.aggregate(total=Sum("price"))
.get("total")
or 0
)

def get_bot_run_count(self) -> int:
return self.saved_runs.filter(
is_api_call=True, price__gt=0, messages__isnull=False
).count()

def get_bot_credit_usage(self) -> int:
return (
self.saved_runs.filter(is_api_call=True, messages__isnull=False)
.aggregate(total=Sum("price"))
.get("total")
or 0
)

def get_or_create_stripe_customer(self) -> stripe.Customer:
customer = None

Expand Down Expand Up @@ -439,6 +469,21 @@ def can_invite(self):
and not self.workspace.is_personal
)

def get_run_count(self) -> int:
return self.workspace.saved_runs.filter(
uid=self.user.uid,
price__gt=0, # proxy for successful runs
is_api_call=False,
).count()

def get_credit_usage(self) -> int:
return (
self.workspace.saved_runs.filter(
uid=self.user.uid, price__gt=0, is_api_call=False
).aggregate(total=Sum("price"))["total"]
or 0
)


class WorkspaceInviteQuerySet(models.QuerySet):
def create_and_send_invite(
Expand Down

0 comments on commit e7bc3b4

Please sign in to comment.