mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-05-03 08:20:40 +02:00
194 lines
5.6 KiB
Python
194 lines
5.6 KiB
Python
import datetime
|
|
from collections import defaultdict
|
|
|
|
from fastapi import APIRouter
|
|
from fastapi import Depends
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ee.onyx.db.analytics import fetch_onyxbot_analytics
|
|
from ee.onyx.db.analytics import fetch_per_user_query_analytics
|
|
from ee.onyx.db.analytics import fetch_persona_message_analytics
|
|
from ee.onyx.db.analytics import fetch_persona_unique_users
|
|
from ee.onyx.db.analytics import fetch_query_analytics
|
|
from onyx.auth.users import current_admin_user
|
|
from onyx.db.engine import get_session
|
|
from onyx.db.models import User
|
|
|
|
router = APIRouter(prefix="/analytics")
|
|
|
|
|
|
_DEFAULT_LOOKBACK_DAYS = 30
|
|
|
|
|
|
class QueryAnalyticsResponse(BaseModel):
|
|
total_queries: int
|
|
total_likes: int
|
|
total_dislikes: int
|
|
date: datetime.date
|
|
|
|
|
|
@router.get("/admin/query")
|
|
def get_query_analytics(
|
|
start: datetime.datetime | None = None,
|
|
end: datetime.datetime | None = None,
|
|
_: User | None = Depends(current_admin_user),
|
|
db_session: Session = Depends(get_session),
|
|
) -> list[QueryAnalyticsResponse]:
|
|
daily_query_usage_info = fetch_query_analytics(
|
|
start=start
|
|
or (
|
|
datetime.datetime.utcnow() - datetime.timedelta(days=_DEFAULT_LOOKBACK_DAYS)
|
|
), # default is 30d lookback
|
|
end=end or datetime.datetime.utcnow(),
|
|
db_session=db_session,
|
|
)
|
|
return [
|
|
QueryAnalyticsResponse(
|
|
total_queries=total_queries,
|
|
total_likes=total_likes,
|
|
total_dislikes=total_dislikes,
|
|
date=date,
|
|
)
|
|
for total_queries, total_likes, total_dislikes, date in daily_query_usage_info
|
|
]
|
|
|
|
|
|
class UserAnalyticsResponse(BaseModel):
|
|
total_active_users: int
|
|
date: datetime.date
|
|
|
|
|
|
@router.get("/admin/user")
|
|
def get_user_analytics(
|
|
start: datetime.datetime | None = None,
|
|
end: datetime.datetime | None = None,
|
|
_: User | None = Depends(current_admin_user),
|
|
db_session: Session = Depends(get_session),
|
|
) -> list[UserAnalyticsResponse]:
|
|
daily_query_usage_info_per_user = fetch_per_user_query_analytics(
|
|
start=start
|
|
or (
|
|
datetime.datetime.utcnow() - datetime.timedelta(days=_DEFAULT_LOOKBACK_DAYS)
|
|
), # default is 30d lookback
|
|
end=end or datetime.datetime.utcnow(),
|
|
db_session=db_session,
|
|
)
|
|
|
|
user_analytics: dict[datetime.date, int] = defaultdict(int)
|
|
for __, ___, ____, date, _____ in daily_query_usage_info_per_user:
|
|
user_analytics[date] += 1
|
|
return [
|
|
UserAnalyticsResponse(
|
|
total_active_users=cnt,
|
|
date=date,
|
|
)
|
|
for date, cnt in user_analytics.items()
|
|
]
|
|
|
|
|
|
class OnyxbotAnalyticsResponse(BaseModel):
|
|
total_queries: int
|
|
auto_resolved: int
|
|
date: datetime.date
|
|
|
|
|
|
@router.get("/admin/onyxbot")
|
|
def get_onyxbot_analytics(
|
|
start: datetime.datetime | None = None,
|
|
end: datetime.datetime | None = None,
|
|
_: User | None = Depends(current_admin_user),
|
|
db_session: Session = Depends(get_session),
|
|
) -> list[OnyxbotAnalyticsResponse]:
|
|
daily_onyxbot_info = fetch_onyxbot_analytics(
|
|
start=start
|
|
or (
|
|
datetime.datetime.utcnow() - datetime.timedelta(days=_DEFAULT_LOOKBACK_DAYS)
|
|
), # default is 30d lookback
|
|
end=end or datetime.datetime.utcnow(),
|
|
db_session=db_session,
|
|
)
|
|
|
|
resolution_results = [
|
|
OnyxbotAnalyticsResponse(
|
|
total_queries=total_queries,
|
|
# If it hits negatives, something has gone wrong...
|
|
auto_resolved=max(0, total_queries - total_negatives),
|
|
date=date,
|
|
)
|
|
for total_queries, total_negatives, date in daily_onyxbot_info
|
|
]
|
|
|
|
return resolution_results
|
|
|
|
|
|
class PersonaMessageAnalyticsResponse(BaseModel):
|
|
total_messages: int
|
|
date: datetime.date
|
|
persona_id: int
|
|
|
|
|
|
@router.get("/admin/persona/messages")
|
|
def get_persona_messages(
|
|
persona_id: int,
|
|
start: datetime.datetime | None = None,
|
|
end: datetime.datetime | None = None,
|
|
_: User | None = Depends(current_admin_user),
|
|
db_session: Session = Depends(get_session),
|
|
) -> list[PersonaMessageAnalyticsResponse]:
|
|
"""Fetch daily message counts for a single persona within the given time range."""
|
|
start = start or (
|
|
datetime.datetime.utcnow() - datetime.timedelta(days=_DEFAULT_LOOKBACK_DAYS)
|
|
)
|
|
end = end or datetime.datetime.utcnow()
|
|
|
|
persona_message_counts = []
|
|
for count, date in fetch_persona_message_analytics(
|
|
db_session=db_session,
|
|
persona_id=persona_id,
|
|
start=start,
|
|
end=end,
|
|
):
|
|
persona_message_counts.append(
|
|
PersonaMessageAnalyticsResponse(
|
|
total_messages=count,
|
|
date=date,
|
|
persona_id=persona_id,
|
|
)
|
|
)
|
|
|
|
return persona_message_counts
|
|
|
|
|
|
class PersonaUniqueUsersResponse(BaseModel):
|
|
unique_users: int
|
|
date: datetime.date
|
|
persona_id: int
|
|
|
|
|
|
@router.get("/admin/persona/unique-users")
|
|
def get_persona_unique_users(
|
|
persona_id: int,
|
|
start: datetime.datetime,
|
|
end: datetime.datetime,
|
|
_: User | None = Depends(current_admin_user),
|
|
db_session: Session = Depends(get_session),
|
|
) -> list[PersonaUniqueUsersResponse]:
|
|
"""Get unique users per day for a single persona."""
|
|
unique_user_counts = []
|
|
daily_counts = fetch_persona_unique_users(
|
|
db_session=db_session,
|
|
persona_id=persona_id,
|
|
start=start,
|
|
end=end,
|
|
)
|
|
for count, date in daily_counts:
|
|
unique_user_counts.append(
|
|
PersonaUniqueUsersResponse(
|
|
unique_users=count,
|
|
date=date,
|
|
persona_id=persona_id,
|
|
)
|
|
)
|
|
return unique_user_counts
|