Unlisted
Edited
May 14, 2024
Insert cell
Insert cell
Insert cell
viewof table = Inputs.table(search, { columns: ["timestamp", "sender", "content"], width: { timestamp: 100, sender: 100}})
Insert cell
messages = parseZoomChat(meeting_saved_chat)
Insert cell
// only messages and replies, no reactions
chats = messages.filter(d => !d.reactionTo)
Insert cell
replies = messages.filter(d => d.replyTo)
Insert cell
reactions = messages.filter(d => d.reactionTo)
Insert cell
messages.filter(d => d.replyTo && !d.parentId)
Insert cell
function parseZoomChat(transcript) {
// Split the transcript at each new timestamp
const messageBlocks = transcript.split(/(?=\d{2}:\d{2}:\d{2} From )/);
const messages = [];
let idCounter = 0;

messageBlocks.forEach(block => {
if (!block.trim()) return;

// Extract timestamp, sender, and the rest of the content
const headerPattern = /^(\d{2}:\d{2}:\d{2}) From (.*?) to Everyone:/;
const headerMatch = block.match(headerPattern);

if (headerMatch) {
const timestamp = headerMatch[1];
const sender = headerMatch[2];
const contentStart = block.indexOf("Everyone:") + "Everyone:".length;
const contentBlock = block.substring(contentStart).trim().replace(/\\r\\n\\t/g, "\n");

// Handle replies and multiline content
const lines = contentBlock.split("\n").map(line => line.trim()).filter(line => line);
const message = {
id: idCounter++,
timestamp,
sender,
content: lines[0],
replyTo: null
};

// Detect "Replying to" in content
if (lines.length > 1 && lines[0].startsWith("Replying to")) {
const replyMatch = lines[0].match(/Replying to "(.*?)"/);
if (replyMatch) {
message.replyTo = replyMatch[1];
message.content = lines.slice(1).join(" "); // Concatenate the rest of the lines as content
}
} else {
message.content = lines.join(" "); // Concatenate all lines for regular messages
}

// Detect "Reacted to"
if (lines[0].startsWith("Reacted to")) {
const reactionMatch = lines[0].match(/Reacted to "(.*?)" with (.*)/);
if (reactionMatch) {
message.reactionTo = reactionMatch[1];
message.emoji = reactionMatch[2];
message.content = `Reacted to "${reactionMatch[1]}" with ${reactionMatch[2]}`;
}
}

messages.push(message);
}

});

// Assign parentId based on content match for replyTo or reactionTo
messages.forEach(message => {
if (message.replyTo || message.reactionTo) {
let searchContent = message.replyTo || message.reactionTo;
searchContent = searchContent.replace("...", "")
searchContent = searchContent.replace("…", "")
const parentMessage = messages.find(m => m.content.indexOf(searchContent) == 0);
if (parentMessage) {
message.parentId = parentMessage.id;
}
}
});
return messages;
}
Insert cell
meeting_saved_chat = FileAttachment("meeting_saved_chat (1).txt").text()
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more