Files
GMW/services/frontend/src/shared/hooks/useMascotSummary.ts
T
MythEclipseandClaude Opus 4.8 4becf0d6f1 refactor: comprehensive codebase cleanup and architecture hardening
- Sprint 1 (Quick Wins): Remove dead analytics modules, fix 4 unresolved
  imports, replace 3 console.warn with logger, remove mock-crc import
- Sprint 2 (Architecture): Create MascotChatRepository, AnalysisRepository,
  3 Zod schemas (mascot-chat, analysis, voice), deduplicate error classes,
  move 3 SQL queries from routes to repository
- Sprint 3 (Complexity): Replace 7 any types with proper interfaces,
  extract 6 helpers from prepareMediaMessage (CC 85 -> ~15)
- Sprint 4 (Config): Remove 22 dead env vars from .env, add 30 missing
  vars to .env.example, standardize naming

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 10:16:04 +07:00

126 lines
3.2 KiB
TypeScript

import { useEffect, useState } from "react";
import type { MessageRecord } from "../api/client";
/**
* useMascotSummary — Generates AI-powered summary/insights from recent messages
* Used by mascot's floating chat bubble to display conversation insights
*/
interface UseMascotSummaryOptions {
messages: MessageRecord[];
enabled?: boolean;
}
const summaryPrompts = [
"📊 Diskusi sangat aktif dengan {count} pesan",
"💬 Topik populer: {topic} ({percentage}%)",
"👥 Partisipan utama: {users}",
"⏰ Aktivitas puncak: {time}",
"🔥 Buzz level: {level}",
"💡 Insight: {insight}",
];
function generateInsight(messages: MessageRecord[]): string {
if (messages.length === 0) {
return "Menunggu pesan...";
}
const totalMessages = messages.length;
const recentMessages = messages.slice(-10);
// Hitung user yang berbeda
const uniqueUsers = new Set(recentMessages.map((m) => m.user_id)).size;
// Hitung average panjang pesan
const avgLength = Math.round(
recentMessages.reduce((sum, m) => sum + (m.content?.length || 0), 0) /
recentMessages.length,
);
// Tentukan tipe percakapan
let insight = "";
if (avgLength > 150) {
insight = "Diskusi mendalam sedang berlangsung";
} else if (avgLength > 80) {
insight = "Percakapan normal dan interaktif";
} else {
insight = "Chat cepat dan ringkas";
}
// Tambah info partisipan
if (uniqueUsers > 5) {
insight += ` • ${uniqueUsers} orang aktif`;
}
// Tambah info volume
if (totalMessages > 50) {
insight += " • Volume tinggi 🔥";
} else if (totalMessages > 20) {
insight += " • Percakapan aktif";
}
return insight;
}
function extractTopics(messages: MessageRecord[]): string {
if (messages.length === 0) return "Tidak ada topik";
// Extract keywords dari recent messages
const recentMessages = messages.slice(-15);
const content = recentMessages
.map((m) => m.content?.toLowerCase() || "")
.join(" ");
// Simple keyword extraction
const keywords = [
{ word: "voice", label: "Voice" },
{ word: "recording", label: "Recording" },
{ word: "audio", label: "Audio" },
{ word: "chat", label: "Chat" },
{ word: "message", label: "Message" },
{ word: "user", label: "User" },
];
for (const { word, label } of keywords) {
if (content.includes(word)) {
return label;
}
}
return "Umum";
}
export function useMascotSummary({
messages,
enabled = true,
}: UseMascotSummaryOptions): string {
const [summary, setSummary] = useState<string>("");
useEffect(() => {
if (!enabled || messages.length === 0) {
setSummary("");
return;
}
// Generate summary berdasarkan messages
const insight = generateInsight(messages);
setSummary(insight);
// Rotate summary setiap 5 detik
const interval = setInterval(() => {
setSummary((prev) => {
if (prev.includes("aktif")) {
return `📈 Total: ${messages.length} pesan`;
} else if (prev.includes("Total")) {
return generateInsight(messages);
}
return prev;
});
}, 5000);
return () => clearInterval(interval);
}, [messages, enabled]);
return summary;
}