← Back to Projects
Commercial Contract • Alive IndustriesContact →

LLM Meeting Intelligence & Audio Summarisation Engine

Architected and shipped an end-to-end meeting summarisation system for ChatSDK. Ingests raw video/audio recordings from Whereby, executes multi-provider LLM summarisation passes with async background polling, and visualises participant insights and structured action items in a Next.js dashboard.

Engineering Architecture

01 / Ingestion

Whereby Webhook & Recording Processing

Listens for Whereby room session completion events, extracts audio streams, and dispatches them to background transcription workers.

02 / LLM Layer

Multi-Provider Summarisation Layer

Chunks transcripts and routes requests across LLM providers with automatic fallback, generating executive takeaways, topic clusters, and categorized action items.

03 / Async Workers

Background Polling & In-Memory Caching

Engineered fault-tolerant job polling to handle variable transcription latency, caching intermediate stages to prevent duplicate LLM calls during network reconnections.

04 / Storage & UI

Drizzle ORM + Meeting Dashboard

Relational PostgreSQL schema managed via Drizzle ORM. Built the Meeting Summary Dashboard UI in Next.js using shadcn/ui, Tailwind CSS, and Framer Motion.

Drizzle ORM Schema Architecture

import { pgTable, text, timestamp, uuid, jsonb, integer } from "drizzle-orm/pg-core";

// Meeting Session Record
export const meetingSessions = pgTable("meeting_sessions", {
  id: uuid("id").defaultRandom().primaryKey(),
  wherebyRoomId: text("whereby_room_id").notNull(),
  recordingUrl: text("recording_url"),
  durationSeconds: integer("duration_seconds"),
  status: text("status", { enum: ["queued", "processing", "completed", "failed"] }).notNull(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
});

// Structured Meeting Insights & Action Items
export const meetingSummaries = pgTable("meeting_summaries", {
  id: uuid("id").defaultRandom().primaryKey(),
  sessionId: uuid("session_id").references(() => meetingSessions.id, { onDelete: "cascade" }),
  executiveSummary: text("executive_summary").notNull(),
  actionItems: jsonb("action_items").$type<Array<{ assignee: string; task: string; priority: "low" | "medium" | "high" }>>(),
  participantMetadata: jsonb("participant_metadata").$type<Array<{ name: string; talkTimePercent: number }>>(),
  tokensUsed: integer("tokens_used"),
  generatedAt: timestamp("generated_at").defaultNow().notNull(),
});

Production Stack

Next.js (App Router)TypeScriptPostgreSQLDrizzle ORMWhereby APIOpenAI / Claudeshadcn/uiFramer MotionBiome