eletrotupi / tcc/ api/src/lib/queue/processors/insights/moodTrend.tsd139cd140eae38d7f5b7000fa39a09c78d163f07
2.4 KB | 81 lines Raw
1
import { prisma } from "@app/lib/prisma";
2
import { InsightType, InsightPeriod, BaseMoodOption } from "@prisma/client";
3
import { InsightPeriodPayload } from "@app/lib/queue/types";
4

5
const MOOD_SCORE: Record<BaseMoodOption, number> = {
6
  GREAT: 5,
7
  GOOD: 4,
8
  NEUTRAL: 3,
9
  SAD: 2,
10
  ANGRY: 1,
11
};
12

13
const avg = (values: number[]) =>
14
  values.reduce((a, b) => a + b, 0) / values.length;
15

16
export async function processMoodTrend({
17
  userId,
18
  periodStart,
19
  periodEnd,
20
}: InsightPeriodPayload): Promise<void> {
21
  const start = new Date(periodStart);
22
  const end = new Date(periodEnd);
23

24
  const moods = await prisma.mood.findMany({
25
    where: { userId, moment: { gte: start, lte: end } },
26
    orderBy: { moment: "asc" },
27
    select: { selectedMood: true, energyLevel: true, moment: true },
28
  });
29

30
  if (moods.length < 3) return;
31

32
  const scores = moods.map((m) => MOOD_SCORE[m.selectedMood]);
33
  const mid = Math.floor(scores.length / 2);
34
  const avgFirst = avg(scores.slice(0, mid));
35
  const avgSecond = avg(scores.slice(mid));
36
  const delta = Math.round(((avgSecond - avgFirst) / avgFirst) * 100);
37

38
  // Dominant mood in the period
39
  const moodCounts = moods.reduce<Partial<Record<BaseMoodOption, number>>>(
40
    (acc, m) => ({ ...acc, [m.selectedMood]: (acc[m.selectedMood] ?? 0) + 1 }),
41
    {},
42
  );
43
  const dominantMood = (
44
    Object.entries(moodCounts) as [BaseMoodOption, number][]
45
  ).sort((a, b) => b[1] - a[1])[0][0];
46

47
  const avgEnergy = avg(moods.map((m) => m.energyLevel));
48

49
  await prisma.insight.upsert({
50
    where: {
51
      userId_type_periodStart: {
52
        userId,
53
        type: InsightType.MOOD_TREND,
54
        periodStart: start,
55
      },
56
    },
57
    update: {
58
      body: buildBody(delta),
59
      metadata: { delta, avgFirst, avgSecond, dominantMood, avgEnergy },
60
      generatedAt: new Date(),
61
    },
62
    create: {
63
      userId,
64
      type: InsightType.MOOD_TREND,
65
      period: InsightPeriod.WEEKLY,
66
      title: "Tendência de Humor",
67
      body: buildBody(delta),
68
      metadata: { delta, avgFirst, avgSecond, dominantMood, avgEnergy },
69
      periodStart: start,
70
      periodEnd: end,
71
    },
72
  });
73
}
74

75
function buildBody(delta: number): string {
76
  if (delta > 10)
77
    return `Seu humor melhorou ${delta}% em relação ao início do período.`;
78
  if (delta < -10)
79
    return `Seu humor caiu ${Math.abs(delta)}% em relação ao início do período.`;
80
  return "Seu humor se manteve estável durante o período.";
81
}