File size: 4,413 Bytes
e3278e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""
Functions for sending Email Alerts
"""

import os
from typing import List, Optional

from litellm._logging import verbose_logger, verbose_proxy_logger
from litellm.proxy._types import WebhookEvent

# we use this for the email header, please send a test email if you change this. verify it looks good on email
LITELLM_LOGO_URL = "https://litellm-listing.s3.amazonaws.com/litellm_logo.png"
LITELLM_SUPPORT_CONTACT = "[email protected]"


async def get_all_team_member_emails(team_id: Optional[str] = None) -> list:
    verbose_logger.debug(
        "Email Alerting: Getting all team members for team_id=%s", team_id
    )
    if team_id is None:
        return []
    from litellm.proxy.proxy_server import prisma_client

    if prisma_client is None:
        raise Exception("Not connected to DB!")

    team_row = await prisma_client.db.litellm_teamtable.find_unique(
        where={
            "team_id": team_id,
        }
    )

    if team_row is None:
        return []

    _team_members = team_row.members_with_roles
    verbose_logger.debug(
        "Email Alerting: Got team members for team_id=%s Team Members: %s",
        team_id,
        _team_members,
    )
    _team_member_user_ids: List[str] = []
    for member in _team_members:
        if member and isinstance(member, dict):
            _user_id = member.get("user_id")
            if _user_id and isinstance(_user_id, str):
                _team_member_user_ids.append(_user_id)

    sql_query = """
        SELECT user_email
        FROM "LiteLLM_UserTable"
        WHERE user_id = ANY($1::TEXT[]);
    """

    _result = await prisma_client.db.query_raw(sql_query, _team_member_user_ids)

    verbose_logger.debug("Email Alerting: Got all Emails for team, emails=%s", _result)

    if _result is None:
        return []

    emails = []
    for user in _result:
        if user and isinstance(user, dict) and user.get("user_email", None) is not None:
            emails.append(user.get("user_email"))
    return emails


async def send_team_budget_alert(webhook_event: WebhookEvent) -> bool:
    """
    Send an Email Alert to All Team Members when the Team Budget is crossed
    Returns -> True if sent, False if not.
    """
    from litellm.proxy.utils import send_email

    _team_id = webhook_event.team_id
    team_alias = webhook_event.team_alias
    verbose_logger.debug(
        "Email Alerting: Sending Team Budget Alert for team=%s", team_alias
    )

    email_logo_url = os.getenv("SMTP_SENDER_LOGO", os.getenv("EMAIL_LOGO_URL", None))
    email_support_contact = os.getenv("EMAIL_SUPPORT_CONTACT", None)

    # await self._check_if_using_premium_email_feature(
    #     premium_user, email_logo_url, email_support_contact
    # )

    if email_logo_url is None:
        email_logo_url = LITELLM_LOGO_URL
    if email_support_contact is None:
        email_support_contact = LITELLM_SUPPORT_CONTACT
    recipient_emails = await get_all_team_member_emails(_team_id)
    recipient_emails_str: str = ",".join(recipient_emails)
    verbose_logger.debug(
        "Email Alerting: Sending team budget alert to %s", recipient_emails_str
    )

    event_name = webhook_event.event_message
    max_budget = webhook_event.max_budget
    email_html_content = "Alert from LiteLLM Server"

    if recipient_emails_str is None:
        verbose_proxy_logger.warning(
            "Email Alerting: Trying to send email alert to no recipient, got recipient_emails=%s",
            recipient_emails_str,
        )

    email_html_content = f"""
    <img src="{email_logo_url}" alt="LiteLLM Logo" width="150" height="50" /> <br/><br/><br/>

    Budget Crossed for Team <b> {team_alias} </b> <br/> <br/>

    Your Teams LLM API usage has crossed it's <b> budget of ${max_budget} </b>, current spend is <b>${webhook_event.spend}</b><br /> <br />

    API requests will be rejected until either (a) you increase your budget or (b) your budget gets reset <br /> <br />

    If you have any questions, please send an email to {email_support_contact} <br /> <br />

    Best, <br />
    The LiteLLM team <br />
    """

    email_event = {
        "to": recipient_emails_str,
        "subject": f"LiteLLM {event_name} for Team {team_alias}",
        "html": email_html_content,
    }

    await send_email(
        receiver_email=email_event["to"],
        subject=email_event["subject"],
        html=email_event["html"],
    )

    return False