eletrotupi / tcc/ api/src/lib/queue/processors/insights/triggerPattern.ts7ff50aa722f838fa59d0afb52d1c2e2b96bf3e22
2.7 KB | 107 lines Raw
1
import { prisma } from "@app/lib/prisma";
2
import { InsightType, InsightPeriod, TriggerType } from "@prisma/client";
3
import { InsightPeriodPayload } from "@app/lib/queue/types";
4

5
const TRIGGER_LABEL: Record<TriggerType, string> = {
6
  SOCIAL: "social",
7
  WORK: "trabalho",
8
  HEALTH: "saúde",
9
  PHYSICAL: "físico",
10
  FAMILY: "família",
11
  THERAPY: "terapia",
12
  INTERNAL: "interno",
13
  OTHER: "outros",
14
};
15

16
// Category counts for a period, most frequent first
17
export function countTriggerCategories(
18
  triggers: { category: TriggerType }[],
19
): [TriggerType, number][] {
20
  const counts = triggers.reduce<Partial<Record<TriggerType, number>>>(
21
    (acc, t) => ({ ...acc, [t.category]: (acc[t.category] ?? 0) + 1 }),
22
    {},
23
  );
24

25
  return (Object.entries(counts) as [TriggerType, number][]).sort(
26
    (a, b) => b[1] - a[1],
27
  );
28
}
29

30
export function triggerPatternBody(
31
  top: TriggerType,
32
  count: number,
33
  total: number,
34
): string {
35
  const pct = Math.round((count / total) * 100);
36
  const label = TRIGGER_LABEL[top];
37
  let template = "";
38

39
  if (top == "OTHER") {
40
    template = `
41
    Gatilhos do tipo "${label}" foram os mais frequentes,
42
    representando ${pct}% dos registros do período.
43
  `
44
  } else {
45
    template = `
46
    Gatilhos de ${label} foram os mais frequentes,
47
    representando ${pct}% dos registros do período.
48
  `
49
  }
50

51
  return template.replace(/\s*\n\s*/g, " ").trim();
52
}
53

54
export async function processTriggerPattern({
55
  userId,
56
  periodStart,
57
  periodEnd,
58
}: InsightPeriodPayload): Promise<void> {
59
  const start = new Date(periodStart);
60
  const end = new Date(periodEnd);
61

62
  const triggers = await prisma.trigger.findMany({
63
    where: { userId, moment: { gte: start, lte: end } },
64
    select: { category: true },
65
  });
66

67
  if (triggers.length === 0) return;
68

69
  const sorted = countTriggerCategories(triggers);
70
  const [topCategory, topCount] = sorted[0];
71
  const distribution = Object.fromEntries(sorted);
72

73
  await prisma.insight.upsert({
74
    where: {
75
      userId_type_periodStart: {
76
        userId,
77
        type: InsightType.TRIGGER_PATTERN,
78
        periodStart: start,
79
      },
80
    },
81
    update: {
82
      body: triggerPatternBody(topCategory, topCount, triggers.length),
83
      metadata: {
84
        topCategory,
85
        topCount,
86
        total: triggers.length,
87
        distribution,
88
      },
89
      generatedAt: new Date(),
90
    },
91
    create: {
92
      userId,
93
      type: InsightType.TRIGGER_PATTERN,
94
      period: InsightPeriod.WEEKLY,
95
      title: "Padrão de Gatilhos",
96
      body: triggerPatternBody(topCategory, topCount, triggers.length),
97
      metadata: {
98
        topCategory,
99
        topCount,
100
        total: triggers.length,
101
        distribution,
102
      },
103
      periodStart: start,
104
      periodEnd: end,
105
    },
106
  });
107
}