BerriAI / litellm

Python SDK, Proxy Server (LLM Gateway) to call 100+ LLM APIs in OpenAI format - [Bedrock, Azure, OpenAI, VertexAI, Cohere, Anthropic, Sagemaker, HuggingFace, Replicate, Groq]
https://docs.litellm.ai/docs/
Other
13.04k stars 1.53k forks source link

[Bug]: No usage info internal user #6298

Open superpoussin22 opened 3 days ago

superpoussin22 commented 3 days ago

What happened?

when user click on usage, nothing appear (no vlaues ) but an error is raised

Relevant log output

error":{"message":"/global/spend/logs Errorrelation \"MonthlyGlobalSpendPerUserPerKey\" does not exist\nTraceback (most recent call last):\n File \"/usr/local/lib/python3.11/site-packages/litellm/proxy/spend_tracking/spend_management_endpoints.py\", line 2008, in global_spend_logs\n response = await global_spend_for_internal_user(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.11/site-packages/litellm/proxy/spend_tracking/spend_management_endpoints.py\", line 1964, in global_spend_for_internal_user\n raise e\n File \"/usr/local/lib/python3.11/site-packages/litellm/proxy/spend_tracking/spend_management_endpoints.py\", line 1959, in global_spend_for_internal_user\n response = await prisma_client.db.query_raw(sql_query, user_id)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.11/site-packages/prisma/client.py\", line 424, in query_raw\n resp = await self._execute(\n ^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.11/site-packages/prisma/client.py\", line 528, in _execute\n return await self._engine.query(builder.build(), tx_id=self._tx_id)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.11/site-packages/prisma/engine/query.py\", line 244, in query\n return await self.request(\n ^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.11/site-packages/prisma/engine/http.py\", line 141, in request\n return utils.handle_response_errors(resp, errors_data)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/lib/python3.11/site-packages/prisma/engine/utils.py\", line 192, in handle_response_errors\n raise exc(error)\nprisma.errors.RawQueryError: relation \"MonthlyGlobalSpendPerUserPerKey\" does not exist\n","type":"internal_error","param":"None","code":"500"}}

Twitter / LinkedIn details

No response

bgeneto commented 2 days ago

I don't know why... but we still have to create the required views for this manually, it follows the script to do so (if using docker see comment at the end).

It would be super nice (although obvious) if litellm added end-users to the database (EndUserTable) every time a request is received with a new user (in the body).

"""
python script to pre-create all views required by LiteLLM Proxy Server
"""

import asyncio
import os
from update_unassigned_teams import apply_db_fixes

# Enter your DATABASE_URL here

from prisma import Prisma

db = Prisma(
    http={
        "timeout": 60000,
    },
)

async def check_view_exists():
    """
    Checks if the LiteLLM_VerificationTokenView and MonthlyGlobalSpend exists in the user's db.

    LiteLLM_VerificationTokenView: This view is used for getting the token + team data in user_api_key_auth

    MonthlyGlobalSpend: This view is used for the admin view to see global spend for this month

    If the view doesn't exist, one will be created.
    """

    # connect to dB
    await db.connect()
    try:
        # Try to select one row from the view
        await db.query_raw("""SELECT 1 FROM "LiteLLM_VerificationTokenView" LIMIT 1""")
        print("LiteLLM_VerificationTokenView Exists!")  # noqa
    except Exception as e:
        # If an error occurs, the view does not exist, so create it
        await db.execute_raw(
            """
                CREATE VIEW "LiteLLM_VerificationTokenView" AS
                SELECT
                v.*,
                t.spend AS team_spend,
                t.max_budget AS team_max_budget,
                t.tpm_limit AS team_tpm_limit,
                t.rpm_limit AS team_rpm_limit
                FROM "LiteLLM_VerificationToken" v
                LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id;
            """
        )

        print("LiteLLM_VerificationTokenView Created!")  # noqa

    try:
        await db.query_raw("""SELECT 1 FROM "MonthlyGlobalSpend" LIMIT 1""")
        print("MonthlyGlobalSpend Exists!")  # noqa
    except Exception as e:
        sql_query = """
        CREATE OR REPLACE VIEW "MonthlyGlobalSpend" AS
        SELECT
        DATE("startTime") AS date,
        SUM("spend") AS spend
        FROM
        "LiteLLM_SpendLogs"
        WHERE
        "startTime" >= (CURRENT_DATE - INTERVAL '30 days')
        GROUP BY
        DATE("startTime");
        """
        await db.execute_raw(query=sql_query)

        print("MonthlyGlobalSpend Created!")  # noqa

    try:
        await db.query_raw("""SELECT 1 FROM "Last30dKeysBySpend" LIMIT 1""")
        print("Last30dKeysBySpend Exists!")  # noqa
    except Exception as e:
        sql_query = """
        CREATE OR REPLACE VIEW "Last30dKeysBySpend" AS
        SELECT
        L."api_key",
        V."key_alias",
        V."key_name",
        SUM(L."spend") AS total_spend
        FROM
        "LiteLLM_SpendLogs" L
        LEFT JOIN
        "LiteLLM_VerificationToken" V
        ON
        L."api_key" = V."token"
        WHERE
        L."startTime" >= (CURRENT_DATE - INTERVAL '30 days')
        GROUP BY
        L."api_key", V."key_alias", V."key_name"
        ORDER BY
        total_spend DESC;
        """
        await db.execute_raw(query=sql_query)

        print("Last30dKeysBySpend Created!")  # noqa

    try:
        await db.query_raw("""SELECT 1 FROM "Last30dModelsBySpend" LIMIT 1""")
        print("Last30dModelsBySpend Exists!")  # noqa
    except Exception as e:
        sql_query = """
        CREATE OR REPLACE VIEW "Last30dModelsBySpend" AS
        SELECT
        "model",
        SUM("spend") AS total_spend
        FROM
        "LiteLLM_SpendLogs"
        WHERE
        "startTime" >= (CURRENT_DATE - INTERVAL '30 days')
        AND "model" != ''
        GROUP BY
        "model"
        ORDER BY
        total_spend DESC;
        """
        await db.execute_raw(query=sql_query)

        print("Last30dModelsBySpend Created!")  # noqa
    try:
        await db.query_raw("""SELECT 1 FROM "MonthlyGlobalSpendPerKey" LIMIT 1""")
        print("MonthlyGlobalSpendPerKey Exists!")  # noqa
    except Exception as e:
        sql_query = """
            CREATE OR REPLACE VIEW "MonthlyGlobalSpendPerKey" AS
            SELECT
            DATE("startTime") AS date,
            SUM("spend") AS spend,
            api_key as api_key
            FROM
            "LiteLLM_SpendLogs"
            WHERE
            "startTime" >= (CURRENT_DATE - INTERVAL '30 days')
            GROUP BY
            DATE("startTime"),
            api_key;
        """
        await db.execute_raw(query=sql_query)

        print("MonthlyGlobalSpendPerKey Created!")  # noqa
    try:
        await db.query_raw(
            """SELECT 1 FROM "MonthlyGlobalSpendPerUserPerKey" LIMIT 1"""
        )
        print("MonthlyGlobalSpendPerUserPerKey Exists!")  # noqa
    except Exception as e:
        sql_query = """
            CREATE OR REPLACE VIEW "MonthlyGlobalSpendPerUserPerKey" AS
            SELECT
            DATE("startTime") AS date,
            SUM("spend") AS spend,
            api_key as api_key,
            "user" as "user"
            FROM
            "LiteLLM_SpendLogs"
            WHERE
            "startTime" >= (CURRENT_DATE - INTERVAL '30 days')
            GROUP BY
            DATE("startTime"),
            "user",
            api_key;
        """
        await db.execute_raw(query=sql_query)

        print("MonthlyGlobalSpendPerUserPerKey Created!")  # noqa

    try:
        await db.query_raw("""SELECT 1 FROM DailyTagSpend LIMIT 1""")
        print("DailyTagSpend Exists!")  # noqa
    except Exception as e:
        sql_query = """
        CREATE OR REPLACE VIEW DailyTagSpend AS
        SELECT
            jsonb_array_elements_text(request_tags) AS individual_request_tag,
            DATE(s."startTime") AS spend_date,
            COUNT(*) AS log_count,
            SUM(spend) AS total_spend
        FROM "LiteLLM_SpendLogs" s
        GROUP BY individual_request_tag, DATE(s."startTime");
        """
        await db.execute_raw(query=sql_query)

        print("DailyTagSpend Created!")  # noqa

    try:
        await db.query_raw("""SELECT 1 FROM "Last30dTopEndUsersSpend" LIMIT 1""")
        print("Last30dTopEndUsersSpend Exists!")  # noqa
    except Exception as e:
        sql_query = """
        CREATE VIEW "Last30dTopEndUsersSpend" AS
        SELECT end_user, COUNT(*) AS total_events, SUM(spend) AS total_spend
        FROM "LiteLLM_SpendLogs"
        WHERE end_user <> '' AND end_user <> user
        AND "startTime" >= CURRENT_DATE - INTERVAL '30 days'
        GROUP BY end_user
        ORDER BY total_spend DESC
        LIMIT 100;
        """
        await db.execute_raw(query=sql_query)

        print("Last30dTopEndUsersSpend Created!")  # noqa

    await apply_db_fixes(db=db)
    return

asyncio.run(check_view_exists())

For docker, do something like this:

docker cp ./create_views.py litellm:/app/db_scripts/
docker exec -it litellm bash -c "cd /app/db_scripts/ && python /app/db_scripts/create_views.py"