70 lines
2.3 KiB
Python
70 lines
2.3 KiB
Python
from datetime import UTC, datetime, timedelta
|
|
|
|
import asyncpg
|
|
|
|
from utils.read.accounts import self_user_id
|
|
from utils.read.models import ResponseStats, VolumeBucket
|
|
|
|
|
|
async def message_volume(
|
|
pool: asyncpg.Pool, account_id: int, chat_id: int, *, days: int = 90
|
|
) -> list[VolumeBucket]:
|
|
self_id = await self_user_id(pool, account_id)
|
|
rows = await pool.fetch(
|
|
"SELECT date_trunc('day', date) AS bucket, count(*) AS total, "
|
|
"count(*) FILTER (WHERE sender_id = $3) AS outgoing "
|
|
"FROM messages "
|
|
"WHERE account_id = $1 AND chat_id = $2 AND date >= $4 "
|
|
"GROUP BY bucket ORDER BY bucket",
|
|
account_id,
|
|
chat_id,
|
|
self_id,
|
|
datetime.now(UTC) - timedelta(days=days),
|
|
)
|
|
return [
|
|
VolumeBucket(
|
|
bucket=row["bucket"],
|
|
total=row["total"],
|
|
outgoing=row["outgoing"],
|
|
incoming=row["total"] - row["outgoing"],
|
|
)
|
|
for row in rows
|
|
]
|
|
|
|
|
|
async def response_stats(
|
|
pool: asyncpg.Pool, account_id: int, chat_id: int
|
|
) -> ResponseStats:
|
|
self_id = await self_user_id(pool, account_id)
|
|
rows = await pool.fetch(
|
|
"WITH ordered AS ("
|
|
"SELECT sender_id, date, "
|
|
"lag(sender_id) OVER w AS prev_sender, "
|
|
"lag(date) OVER w AS prev_date "
|
|
"FROM messages "
|
|
"WHERE account_id = $1 AND chat_id = $2 AND sender_id IS NOT NULL "
|
|
"WINDOW w AS (ORDER BY date, message_id)), "
|
|
"resp AS ("
|
|
"SELECT (sender_id = $3) AS is_mine, "
|
|
"EXTRACT(EPOCH FROM (date - prev_date)) AS secs "
|
|
"FROM ordered "
|
|
"WHERE prev_sender IS NOT NULL AND prev_sender <> sender_id) "
|
|
"SELECT is_mine, count(*) AS n, "
|
|
"percentile_cont(0.5) WITHIN GROUP (ORDER BY secs) AS median_secs "
|
|
"FROM resp GROUP BY is_mine",
|
|
account_id,
|
|
chat_id,
|
|
self_id,
|
|
)
|
|
stats = ResponseStats(
|
|
mine_median_seconds=None, mine_count=0, their_median_seconds=None, their_count=0
|
|
)
|
|
for row in rows:
|
|
if row["is_mine"]:
|
|
stats.mine_median_seconds = row["median_secs"]
|
|
stats.mine_count = row["n"]
|
|
else:
|
|
stats.their_median_seconds = row["median_secs"]
|
|
stats.their_count = row["n"]
|
|
return stats
|