Skip to content

Commit

Permalink
feat: show most active participants and groups, word cloud in Ended S…
Browse files Browse the repository at this point in the history
…tage (#91)

* feat: show most active participants and groups in Ended Stage

* feat: show word cloud in Ended Stage
  • Loading branch information
howard9199 authored Dec 25, 2024
1 parent 5b119a5 commit cf58cb2
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 12 deletions.
52 changes: 49 additions & 3 deletions src/lib/components/session/HostView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
avatar?: string;
}>;
} | null>(null);
let conversationsData = $state<Array<Conversation>>([]);
let keywordData = $state<Record<string, number>>({});
onMount(() => {
const unsubscribes: (() => void)[] = [];
Expand Down Expand Up @@ -408,6 +410,50 @@
notifications.error('Failed to change stage');
}
}
async function loadConversationsData() {
try {
if (!$page.params.id) return;
const response = await fetch(
`/api/session/${$page.params.id}/conversations/most-active-participants`
);
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || '無法獲取對話資料');
}
conversationsData = await response.json();
console.log(conversationsData);
} catch (error) {
console.error('無法加載對話資料:', error);
notifications.error('無法加載對話資料');
}
}
async function loadKeywordData() {
try {
if (!$page.params.id) return;
const response = await fetch(`/api/session/${$page.params.id}/conversations/keywords`);
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || '無法獲取關鍵字資料');
}
keywordData = await response.json();
} catch (error) {
console.error('無法加載關鍵字資料:', error);
notifications.error('無法加載關鍵字資料');
}
}
$effect(() => {
if ($session?.status === 'ended') {
loadConversationsData();
loadKeywordData();
}
});
</script>

<main class="mx-auto max-w-7xl px-4 py-16">
Expand Down Expand Up @@ -454,14 +500,14 @@
<h2 class="mb-4 text-xl font-semibold">Final Summary</h2>
<div class="flex w-full flex-col gap-4">
<div class="h-96">
<WordCloud />
<WordCloud words={keywordData} />
</div>
<div class="flex w-full gap-4">
<div class="h-96 flex-1">
<MostActiveParticipants />
<MostActiveParticipants conversations={conversationsData} />
</div>
<div class="h-96 flex-1">
<MostActiveGroups />
<MostActiveGroups groups={$groups} />
</div>
</div>
</div>
Expand Down
20 changes: 11 additions & 9 deletions src/lib/components/session/MostActiveParticipants.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
// Add user name mapping store
let userNames = new Map<string, string>();
let loading = true;
function getColorByRatio(ratio: number): string {
const h = 12;
Expand All @@ -24,7 +23,7 @@
}
async function updateChart() {
if (!container) return;
if (!container || !conversations || conversations.length === 0) return;
if (!chart) {
chart = echarts.init(container);
Expand All @@ -46,7 +45,6 @@
// Load user profiles if not cached
const userIds = Object.keys(participantData);
loading = true;
await Promise.all(
userIds.map(async (uid) => {
Expand All @@ -57,13 +55,11 @@
})
);
loading = false;
const sortedData = Object.entries(participantData)
.sort(([, a], [, b]) => b - a)
.slice(0, 5)
.reverse();
console.log('sortedData', sortedData);
const maxValue = sortedData[sortedData.length - 1][1];
chart.setOption({
Expand Down Expand Up @@ -111,18 +107,24 @@
});
$effect(() => {
if (!loading && conversations && chart) {
if (conversations && conversations.length > 0) {
updateChart();
}
});
onMount(() => {
updateChart();
if (conversations && conversations.length > 0) {
updateChart();
}
});
onDestroy(() => {
chart?.dispose();
});
</script>

<div bind:this={container} class="h-full w-full"></div>
<div bind:this={container} class="h-full w-full">
{#if !conversations || conversations.length === 0}
<div class="flex h-full w-full items-center justify-center text-gray-500">暫無數據</div>
{/if}
</div>
33 changes: 33 additions & 0 deletions src/lib/utils/firestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,36 @@ export async function getSessionData(

return session.data() as Session;
}

export async function getConversationsFromAllParticipantsData(
id: string
): Promise<Array<Conversation & { groupId: string; conversationId: string }>> {
// 先獲取所有群組
const groupsRef = getGroupsRef(id);
const groups = await groupsRef.get();

if (groups.empty) {
throw error(404, 'No groups found');
}

// 獲取每個群組中的所有對話
const conversationsPromises = groups.docs.map(async (groupDoc) => {
const conversationsRef = getConversationsRef(id, groupDoc.id);
const conversations = await conversationsRef.get();

return conversations.docs.map((doc) => ({
...(doc.data() as Conversation),
groupId: groupDoc.id,
conversationId: doc.id
}));
});

const allConversations = await Promise.all(conversationsPromises);
const flattenedConversations = allConversations.flat();

if (flattenedConversations.length === 0) {
throw error(404, 'No conversations found');
}

return flattenedConversations;
}
27 changes: 27 additions & 0 deletions src/routes/api/session/[id]/conversations/keywords/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getGroupsData, getGroupsRef } from '$lib/utils/firestore';
import { error, json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
try {
const groupsRef = getGroupsRef(params.id);
const groups = await getGroupsData(groupsRef);

// 建立關鍵字頻率統計
const keywordFrequency: Record<string, number> = {};

// 遍歷所有群組的關鍵字
groups.forEach((group) => {
if (group.keywords) {
Object.entries(group.keywords).forEach(([, count]) => {
keywordFrequency[count] = (keywordFrequency[count] || 0) + 1;
});
}
});

return json(keywordFrequency);
} catch (err) {
console.error('Error fetching data:', err);
throw error(500, '無法獲取資料');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getConversationsFromAllParticipantsData } from '$lib/utils/firestore';
import { error, json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
try {
const conversations = await getConversationsFromAllParticipantsData(params.id);
return json(conversations);
} catch (err) {
console.error('Error fetching data:', err);
throw error(500, '無法獲取資料');
}
};

0 comments on commit cf58cb2

Please sign in to comment.