0% found this document useful (0 votes)
28 views57 pages

Smart Meeting Assistant Presentation Guide

The Smart Meeting Assistant presentation outlines an AI-powered platform for real-time meeting transcription and Q&A, detailing its architecture, technology stack, and implementation. Key features include live transcription, an AI assistant for Q&A, and a user-friendly interface built with Next.js, React, and Stream.io. The document also discusses challenges faced during development and solutions implemented to enhance user experience and system performance.

Uploaded by

vadapav111204
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views57 pages

Smart Meeting Assistant Presentation Guide

The Smart Meeting Assistant presentation outlines an AI-powered platform for real-time meeting transcription and Q&A, detailing its architecture, technology stack, and implementation. Key features include live transcription, an AI assistant for Q&A, and a user-friendly interface built with Next.js, React, and Stream.io. The document also discusses challenges faced during development and solutions implemented to enhance user experience and system performance.

Uploaded by

vadapav111204
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Smart Meeting Assistant - 30 Minute Presentation Guide

📋 Table of Contents
1. Introduction & Demo

2. Project Overview & Architecture

3. Technology Stack Deep Dive

4. Frontend Implementation

5. Backend Implementation

6. Key Features & Flow

7. Challenges & Solutions

8. Q&A Preparation

1. Introduction & Demo (3-4 minutes)

Opening Statement

"Good [morning/afternoon] everyone. Today I'm excited to present my Smart Meeting Assistant - an AI-
powered real-time meeting transcription and Q&A platform that transforms how we capture and
interact with meeting content."

Quick Demo Points (Show Live or Recording)

1. Home Page Entry

"Users can enter their name or join anonymously"


"The system automatically handles both cases"

2. Meeting Room Interface


"Real-time video calling with [Link]"

"Live transcription panel on the right"


"Clean, professional UI with gradient backgrounds"

3. Live Transcription

"As participants speak, transcripts appear in real-time"


"Each message shows speaker name, timestamp, and content"

"Auto-scrolls to latest message"


4. AI Assistant Q&A
"Say 'Hey Assistant' followed by your question"

"The AI bot responds based on meeting context"


"Example: 'Hey Assistant, what are the action items?'"

Hook Statement

"This isn't just another video chat app - it's an intelligent meeting companion that listens, transcribes,
and answers questions based on your conversation context."

2. Project Overview & Architecture (4-5 minutes)

High-Level Architecture

"Let me walk you through the system architecture using this sequence diagram."

Component Overview

Frontend ([Link] + React)



Backend API ([Link] API Routes)

[Link] Services (Video + Chat)

Python Vision Agent (Gemini AI)

Key Components Explanation

1. User Entry Flow

Point to diagram: User → HomePage

"When a user visits the application, they're greeted with a simple name entry form. The system has built-
in intelligence:"

If name is provided → use that name

If blank → automatically set to "Anonymous"

This ensures no user is blocked from joining

2. Authentication & Token Management

Point to diagram: HomePage → TokenAPI


"Once a user enters or skips the name, the system:"

Creates a unique user ID (lowercase, hyphenated)

Sends request to /api/token endpoint

Backend generates a secure Stream token with 24-hour validity

Includes clock skew handling (10-second offset) to prevent authentication issues

Technical Detail:

javascript

const iatTime = now - 10; // Prevents clock skew issues


const token = [Link]({
user_id: userId,
validity_in_seconds: 24 * 60 * 60,
iat: iatTime
} );

3. Stream Client Initialization

Point to diagram: MeetingPage → StreamUser → StreamProvider

"With the token, we initialize two critical clients:"

Video Client: Handles video calls, screen sharing, controls

Chat Client: Manages real-time messaging (currently prepared for future features)

"The StreamProvider component wraps the entire meeting interface, providing context to all child
components."

4. Meeting Room Architecture

Point to diagram: StreamProvider → MeetingRoom

"The MeetingRoom component is the heart of the application:"

Creates or joins an existing call using the call ID

Automatically starts closed captions for transcription

Manages participant lifecycle (join/leave events)

Renders the video layout and transcript panel side-by-side

5. Live Transcription System


Point to diagram: MeetingRoom → TranscriptPanel

"[Link] provides closed caption events that we capture in real-time:"

Listen for call.closed_caption events

Extract speaker name, text, and timestamp

Store in React state array

Auto-scroll to latest entry

Beautiful UI with speaker avatars and timestamps

6. Vision Agent Integration

Point to diagram: VisionAgent

"Here's where it gets really interesting - the Python backend:"

A Vision Agent bot joins the call as a virtual participant

Uses Google's Gemini Realtime API for speech understanding

Listens silently to entire conversation

Maintains full meeting transcript in memory

Activates ONLY when someone says "Hey Assistant"

"The agent has strict behavioral rules:"

python

instructions="""
CRITICAL RULES - FOLLOW EXACTLY:
1. YOU MUST NEVER SPEAK unless someone says "Hey Assistant"
2. DO NOT respond to conversations between users
3. ONLY RESPOND when you explicitly hear "Hey Assistant"
"""

7. Q&A System

Point to diagram: User ↔ VisionAgent

"When 'Hey Assistant' is detected:"

1. Extract the question after "Hey Assistant"

2. Build context from entire meeting transcript

3. Generate response using Gemini AI


4. Speak answer back into the call

5. Response appears in video as audio

Architecture Benefits

"This architecture provides:"

Scalability: [Link] handles infrastructure

Real-time Performance: WebRTC for video, WebSocket for events

AI Intelligence: Context-aware responses

Modularity: Each component has single responsibility

Security: Token-based authentication

3. Technology Stack Deep Dive (5-6 minutes)

Frontend Stack

[Link] 14 (App Router)

"I chose [Link] for several reasons:"

1. Server-Side Rendering (SSR)

Better SEO (though not critical for this use case)

Faster initial page load

Environment variable security

2. File-based Routing

/app/[Link] → Home page

/app/meeting/[id]/[Link] → Dynamic meeting routes

/app/api/token/[Link] → API endpoint

3. API Routes
Backend functionality without separate server

Token generation endpoint lives in the same codebase

Simplified deployment

Code Example:
javascript

// Dynamic routing in [Link] App Router


// File: app/meeting/[id]/[Link]
const callId = [Link]; // Automatically extracted from URL

React 18

"React powers our interactive UI with:"

Hooks for State Management

useState for local component state

useEffect for side effects (API calls, event listeners)

useRef for preventing duplicate operations

Component Architecture
HomePage: Name entry form

MeetingPage: Orchestrates authentication

StreamProvider: Context provider for Stream clients

MeetingRoom: Video call interface

TranscriptPanel: Live transcript display

Tailwind CSS

"For styling, I used Tailwind CSS because:"

Utility-first approach speeds up development

No CSS file management

Built-in responsive design

Easy theming with custom colors

Example:

javascript

className="bg-gray-800 rounded-2xl border border-gray-700 shadow-2xl"

[Link] Video SDK

"[Link] is the backbone of our real-time features:"


Key Features Used:

1. Video Calling

javascript

const myCall = [Link]('default', callId);


await [Link]();
await [Link]();

2. Closed Captions / Transcription

javascript

await [Link]({ language: 'en' });

3. Event System

javascript

[Link]('call.closed_caption', handleClosedCaption);
[Link]('call.session_ended', handleSessionEnd);

4. Pre-built UI Components

SpeakerLayout : Video grid layout

CallControls : Mute, video toggle, leave buttons

StreamTheme : Consistent theming

"Why [Link] over alternatives like Twilio or Agora?"

More generous free tier

Better documentation

Built-in closed captions support

React SDK is production-ready

Backend Stack

Python 3.x
"The AI agent is built with Python because:"

Rich AI/ML ecosystem

Vision Agents library support

Async/await for concurrent operations

Easy integration with Google Gemini

Vision Agents Framework

"This is a specialized framework for building AI agents that interact with real-time media:"

Core Concepts:

1. Edge Connections
Connects to [Link] infrastructure
Handles media streaming

Manages real-time events

2. Agent Definition

python

agent = [Link](
edge=[Link](),
agent_user=User(id="meeting-assistant-bot"),
instructions="...", # Behavior rules
llm=[Link](fps=0)
)

3. Event-Driven Architecture

Subscribe to specific events

React to participants joining/leaving

Process speech transcriptions

Handle errors gracefully

Google Gemini Realtime API

"For AI capabilities, I integrated Google's Gemini:"

Why Gemini over GPT or Claude?

Real-time audio processing


Low latency responses

Multimodal understanding (text + audio)

Cost-effective for this use case

Configuration:

python

llm=[Link](fps=0) # fps=0 means audio-only mode

Event Handling System

"The agent subscribes to multiple event types:"

1. Session Events

python

@[Link]
async def handle_session_started(event: CallSessionStartedEvent):
meeting_data["is_active"] = True
# Initialize chat channel for future features

2. Participant Events

python

@[Link]
async def handle_participant_joined(event):
# Log participant name
# Update internal state

3. Transcription Events

python

@[Link]
async def handle_transcript(event: RealtimeUserSpeechTranscriptionEvent):
# Store in meeting_data["transcript"]
# Check for "Hey Assistant" trigger

4. Error Events
python

@[Link]
async def handle_errors(event: PluginErrorEvent):
if event.is_fatal:
# Handle fatal errors

Development & Deployment Tools

Environment Configuration

"Both frontend and backend use environment variables:"

Frontend (.[Link]):

bash

NEXT_PUBLIC_STREAM_API_KEY=your_key
NEXT_PUBLIC_CALL_ID=default_meeting_id
STREAM_API_SECRET=your_secret

Backend (.env):

bash

STREAM_API_KEY=your_key
STREAM_API_SECRET=your_secret
CALL_ID=meeting_id
GOOGLE_API_KEY=gemini_key

Version Control

Git for source control

Separate frontend and backend directories

.gitignore for node_modules and .env files

4. Frontend Implementation Walkthrough (8-10 minutes)

Component 1: Home Page ( app/[Link] )

"Let's start with the entry point of our application."


Code Walkthrough

javascript

export default function Home() {


const [username, setUsername] = useState("");
const router = useRouter();

const handleJoin = () => {


const nameToUse = [Link]() === "" ? "Anonymous" : [Link]();
const meetingId = [Link].NEXT_PUBLIC_CALL_ID;
[Link](`/meeting/${meetingId}?name=${encodeURIComponent(nameToUse)}`);
}

Key Points:

1. State Management
Single state variable for username
Simple controlled input component

2. Name Validation
Trim whitespace

Default to "Anonymous" if empty


URL encode for safe navigation

3. Navigation

Use [Link] useRouter hook


Programmatic navigation to meeting page

Pass name as query parameter

UI Design:

Centered card layout

Dark theme with gradient background

Responsive design

Clear call-to-action button

Component 2: Meeting Page ( app/meeting/[id]/[Link] )

"This is the orchestrator component that handles authentication and setup."


Code Walkthrough

Step 1: Extract URL Parameters

javascript

const params = useParams();


const searchParams = useSearchParams();
const callId = [Link]; // From URL: /meeting/[id]
const name = [Link]("name") || "anonymous";

Step 2: Create User Object

javascript

useEffect(() => {
setUser({
id: [Link]().replace(/\s+/g, "-"),
name,
} );
}, [name]);

"Why lowercase and hyphenate?"

[Link] user IDs should be URL-safe

Consistent format prevents issues

Example: "John Doe" → "john-doe"

Step 3: Fetch Authentication Token

javascript
useEffect(() => {
if (!user) return;

fetch("/api/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: [Link]({ userId: [Link] }),
})
.then((res) => [Link]())
.then((data) => {
if ([Link]) setToken([Link]);
else setError("No token returned");
})
.catch((err) => setError([Link]));
}, [user]);

"This is a critical security step:"

Never expose API secrets in frontend

Backend generates token server-side

Token is valid for 24 hours

If token fetch fails, show error UI

Step 4: Render Based on State

javascript

if (error) return <ErrorUI />;


if (!token || !user) return <LoadingUI />;
return (
<StreamProvider user={user} token={token}>
<MeetingRoom callId={callId} onLeave={handleLeave} userId={[Link]} />
</StreamProvider>
);

"Progressive rendering ensures users see appropriate feedback at each stage."

Component 3: Stream Provider ( app/components/[Link] )

"This component initializes the Stream clients and provides them via React Context."

Code Walkthrough
javascript

export default function StreamProvider({ children, user, token }) {


const { videoClient } = useStreamClients({ apiKey, user, token });

if (!videoClient) {
return <LoadingSpinner />;
}

return (
<StreamVideo client={videoClient}>
{children}
</StreamVideo>
);
}

"Simple but crucial - it wraps children with Stream's context provider."

Component 4: Custom Hook ( app/hooks/[Link] )

"This is where the actual client initialization happens."

Code Walkthrough

Video Client Initialization:

javascript

const tokenProvider = () => [Link](token);


myVideoClient = new StreamVideoClient({
apiKey,
user,
tokenProvider,
} );

Key Points:

Token provider is a function (for future token refresh)

User object contains { id, name }

Client creation is asynchronous

Chat Client Initialization:

javascript
myChatClient = [Link](apiKey);

if (![Link]) {
await [Link](user, token);
}

"The chat client uses singleton pattern:"

getInstance returns existing instance if available

Only connect if not already connected

Prevents duplicate connections on re-renders

Cleanup Handling:

javascript

return () => {
isMounted = false;
// Don't disconnect on unmount - causes issues with reconnection
};

"Notice we DON'T disconnect on unmount:"

React Strict Mode causes double mounting in dev

Disconnecting causes authentication loops

Clients remain connected throughout session

Component 5: Meeting Room ( app/components/[Link] )

"This is the main meeting interface."

Code Walkthrough

Call Initialization:

javascript
const myCall = [Link]('default', callId);

await [Link]({
data: {
created_by_id: userId,
},
} );
await [Link]();
await [Link]({ language: 'en' });

Step-by-step:

1. Create call reference with type and ID

2. Get existing call or create new one

3. Join the call (establishes WebRTC connection)

4. Start closed captions for transcription

Event Handling:

javascript

[Link]("call.session_ended", () => {
[Link]("Session ended");
onLeave?.();
} );

Ref Pattern for Preventing Duplicates:

javascript

const joinedRef = useRef(false);


const leavingRef = useRef(false);

useEffect(() => {
if ([Link]) return; // Prevent double join
[Link] = true;
// ... initialization
}, [client, callId, userId]);

"Why use refs instead of state?"

Refs don't trigger re-renders

Prevent duplicate operations


Essential for React Strict Mode compatibility

Layout Structure:

javascript

<div className="grid grid-cols-1 lg:grid-cols-[1fr_420px] gap-6">


<div>
<SpeakerLayout /> {/* Video grid */}
<CallControls onLeave={handleLeaveClick} />
</div>
<TranscriptPanel /> {/* Live transcripts */}
</div>

"Responsive design:"

Single column on mobile

Two-column on desktop (video + transcript)

Video takes remaining space, transcript fixed 420px

Component 6: Transcript Panel ( app/components/[Link] )

"The live transcription interface."

Code Walkthrough

Event Listening:

javascript
useEffect(() => {
if (!call) return;

const handleClosedCaption = (event) => {


if (event.closed_caption) {
const newTranscript = {
text: event.closed_caption.text,
speaker: event.closed_caption.user?.name || "Unknown",
timestamp: new Date(event.closed_caption.start_time).toLocaleTimeString(),
};
setTranscripts((prev) => [...prev, newTranscript]);
}
};

[Link]("call.closed_caption", handleClosedCaption);
return () => [Link]("call.closed_caption", handleClosedCaption);
}, [call]);

Key Points:

1. Event Subscription
Listen for call.closed_caption events

Extract text, speaker, timestamp


Add to transcript array

2. Data Structure

javascript

{
text: "Hello everyone",
speaker: "John Doe",
timestamp: "2:45:30 PM"
}

3. Cleanup

Remove event listener on unmount

Prevents memory leaks

Auto-scroll Feature:

javascript
const transcriptEndRef = useRef(null);

useEffect(() => {
[Link]?.scrollIntoView({ behavior: "smooth" });
}, [transcripts]);

// In JSX:
<div ref={transcriptEndRef} />

"Every time transcripts update, scroll to bottom smoothly."

UI Components:

1. Header
Shows "Live Transcript" title

Message count
Green "Live" indicator with pulse animation

2. Empty State
Shows when no transcripts yet
Microphone icon

Instructional text

3. Transcript Items

Speaker avatar (first letter of name)


Speaker name in blue
Timestamp in gray

Message text
Hover effects for interactivity

Frontend Data Flow Summary

"Let me summarize the complete frontend flow:"


User enters name

HomePage creates user ID

Navigate to /meeting/[id]?name=...

MeetingPage fetches token from API

useStreamClients initializes Video & Chat clients

StreamProvider wraps MeetingRoom with context

MeetingRoom joins call & starts captions

TranscriptPanel listens for caption events

Display transcripts in real-time

5. Backend Implementation Walkthrough (6-8 minutes)

API Route: Token Generation ( app/api/token/[Link] )

"This is our only backend API endpoint - and it's critical for security."

Code Walkthrough

Step 1: Initialize Stream Server Client

javascript

const serverClient = new StreamClient(apiKey, apiSecret);

"This client has elevated privileges:"

Can create users

Can generate tokens

Should NEVER be exposed to frontend

Step 2: Create/Upsert User

javascript
const newUser = {
id: userId,
role: "admin",
name: userId,
};
await [Link]([newUser]);

"upsertUsers means:"

Create user if doesn't exist

Update user if already exists

No errors for duplicate creation

Step 3: Generate Token with Clock Skew Fix

javascript

const now = [Link]([Link]() / 1000);


const iatTime = now - 10; // 10 seconds in past

const token = [Link]({


user_id: userId,
validity_in_seconds: 24 * 60 * 60, // 24 hours
iat: iatTime, // Issued At time
} );

"This was a critical bug fix:"

Problem:

JWT tokens have an iat (issued at) claim

If server clock is slightly ahead of Stream's clock

Token validation fails with "Token used before issued"

Solution:

Subtract 10 seconds from current time

Ensures token's iat is always in the past

Accounts for clock drift between servers

Step 4: Return Token


javascript

return [Link]({ token });

Error Handling:

javascript

try {
// ... token generation
} catch (error) {
[Link]("Token generation error:", error);
return [Link](
{ error: "Failed to generate token", details: [Link] },
{ status: 500 }
);
}

Python Vision Agent ( backend/[Link] )

"Now let's look at the AI agent backend."

Architecture Overview

"The agent runs as a separate Python process that:"

1. Connects to the same Stream call

2. Joins as a virtual participant

3. Listens to all audio

4. Processes speech with Gemini

5. Responds when triggered

Code Walkthrough

Agent Initialization:

python
agent = [Link](
edge=[Link](),
agent_user=User(
id="meeting-assistant-bot",
name="Meeting Assistant"
),
instructions="""[System prompt]""",
llm=[Link](fps=0),
)

Components:

edge: Connection to Stream infrastructure

agent_user: Bot's identity in the call

instructions: Behavioral rules (system prompt)

llm: AI model for processing/generation

Critical Instructions:

python

instructions="""
CRITICAL RULES - FOLLOW EXACTLY:
1. YOU MUST NEVER SPEAK unless someone says "Hey Assistant"
2. DO NOT respond to conversations between users
3. DO NOT acknowledge anything users say to each other
"""

"These rules are essential:"

Without them, bot would interrupt conversations

Would respond to rhetorical questions

Would create awkward meeting dynamics

"This took significant prompt engineering to get right!"

Event Handlers

1. Session Started Handler:

python
@[Link]
async def handle_session_started(event: CallSessionStartedEvent):
meeting_data["is_active"] = True
[Link]("🎙️ Meeting started")

# Initialize chat channel for future messaging features


channel = [Link]("messaging", call_id)
await [Link]()
meeting_data["channel"] = channel

"When the meeting starts:"

Set active flag

Initialize chat channel (prepared for future features)

Log the event

2. Participant Joined Handler:

python

@[Link]
async def handle_participant_joined(event: CallSessionParticipantJoinedEvent):
if [Link] == "meeting-assistant-bot":
return # Ignore self
participant_name = [Link]
[Link](f"👤 Participant joined: {participant_name}")

"Track who's in the meeting:"

Ignore the bot itself

Log other participants

Could be used for attendance tracking

3. Transcription Handler (Most Important):

python
@[Link]
async def handle_transcript(event: RealtimeUserSpeechTranscriptionEvent):
if not [Link] or len([Link]()) == 0:
return

speaker = event.participant_id
transcript_text = [Link]

# Store transcript
meeting_data["transcript"].append({
"speaker": speaker,
"text": transcript_text,
"timestamp": [Link]
})

[Link](f"📝 [{speaker}]: {transcript_text}")

"Every speech segment is captured:"

Filter empty transcripts

Store speaker, text, timestamp

Build up meeting transcript in memory

This becomes context for Q&A

4. Q&A Trigger Detection:

python
# Inside handle_transcript function
if transcript_text.lower().startswith("hey assistant"):
question = transcript_text[13:].strip() # Remove "hey assistant"

if question:
# Build context from transcript
context = "MEETING TRANSCRIPT:\n\n"
for entry in meeting_data["transcript"]:
context += f"[{entry['speaker']}]: {entry['text']}\n"

prompt = f"""
{context}

USER QUESTION: {question}

Answer based ONLY on the meeting transcript above.


Be concise and helpful.
"""

await agent.simple_response(prompt)

"How Q&A works:"

1. Detect "hey assistant" trigger (case-insensitive)

2. Extract question after trigger phrase

3. Build context from entire meeting transcript

4. Create prompt with context + question

5. Call simple_response to generate answer

6. Agent speaks the answer into the call

Example Flow:
User: "Hey Assistant, what did John say about the budget?"

Context Built:
[John]: "The budget is $50,000"
[Jane]: "That seems reasonable"
[John]: "We should allocate 30% to marketing"

Prompt to Gemini:
"MEETING TRANSCRIPT:
[John]: The budget is $50,000
[Jane]: That seems reasonable
[John]: We should allocate 30% to marketing

USER QUESTION: what did John say about the budget?

Answer based ONLY on the meeting transcript above."

Gemini Response:
"John mentioned that the budget is $50,000 and suggested allocating 30% to marketing."

[Agent speaks this response in the call]

5. Session Ended Handler:

python

@[Link]
async def handle_session_ended(event: CallSessionEndedEvent):
meeting_data["is_active"] = False
[Link]("🛑 Meeting ended")
[Link](f"📊 Final Stats:")
[Link](f" - Transcript entries: {len(meeting_data['transcript'])}")

"Cleanup and logging when meeting ends."

Agent Lifecycle

Joining the Call:

python
await agent.create_user() # Register bot user with Stream
call = [Link]("default", call_id)

async with [Link](call):


[Link]("🎙️ MEETING ASSISTANT ACTIVE!")
await [Link]() # Wait until meeting ends

"The async with context manager:"

Automatically handles join/leave

Ensures cleanup on exit

Manages connection lifecycle

Meeting Summary Feature

Post-Meeting Summary:

python

def print_meeting_summary():
print("\n📋 MEETING SUMMARY")
print(f"📝 Transcript ({len(meeting_data['transcript'])} entries):")
for entry in meeting_data['transcript']:
print(f"[{entry['speaker']}]: {entry['text']}")

"When agent exits, prints full meeting transcript to console."

Future Enhancement:

Could send this via email

Store in database

Generate PDF report

Create action items list

Backend Architecture Benefits

"Why separate Python backend instead of all [Link]?"

1. Vision Agents Framework


Python-only library
Specialized for real-time media AI agents

Rich event system

2. AI/ML Ecosystem

Better Python support for Gemini, GPT, etc.


NumPy, TensorFlow if we add ML features
Audio processing libraries

3. Separation of Concerns
Frontend handles UI/UX

Node backend handles web API


Python backend handles AI processing

4. Independent Scaling

Can deploy agent separately


Multiple agents for large meetings

Doesn't affect frontend performance

6. Key Features & Flow Analysis (4-5 minutes)

Feature 1: Anonymous Join

"Users can join without creating an account:"

Implementation:

javascript

const nameToUse = [Link]() === "" ? "Anonymous" : [Link]();

Benefits:

Zero friction onboarding

Privacy for users who prefer anonymity

Still unique via system-generated ID

Technical Detail:

Anonymous users still get unique IDs


Multiple anonymous users don't conflict

Transcript shows "Anonymous" as speaker name

Feature 2: Real-Time Transcription

"Powered by [Link]'s closed captions API:"

How it works:

1. Stream processes audio using speech-to-text

2. Generates closed caption events

3. Frontend receives events via WebSocket

4. Displays in transcript panel

5. Backend Vision Agent also receives events

Accuracy:

Uses industry-standard speech recognition

Supports multiple languages (we use English)

Real-time with < 1 second latency

Feature 3: AI Q&A System

"Context-aware question answering:"

Trigger Mechanism:

Wake word: "Hey Assistant"

Natural language questions

Example: "Hey Assistant, summarize the last 5 minutes"

Context Building:

Full meeting transcript in memory

Speaker attribution

Timestamps for temporal queries


AI Model:

Google Gemini Realtime API

Optimized for conversational responses

Audio-native processing

Response Types:

1. Factual: "What did John say about X?"

2. Summarization: "Summarize the discussion"

3. Action Items: "What are the next steps?"

4. Clarification: "Who agreed to do the presentation?"

Feature 4: Professional UI/UX

Design Principles:

1. Dark Theme
Reduces eye strain

Professional appearance

Modern aesthetic

2. Gradient Backgrounds

Visual interest
Depth perception

Brand identity

3. Responsive Layout

Mobile-first approach
Tablet optimization
Desktop maximization

4. Loading States
Spinner animations

Progress feedback
Error boundaries

5. Smooth Transitions
Fade-in animations
Scroll behavior

Hover effects

Feature 5: Session Management

Join Flow:

1. Enter name (or skip)


2. Generate user ID
3. Fetch auth token
4. Initialize clients
5. Join call
6. Start captions
7. Begin transcription

Leave Flow:

1. Click "Leave" button


2. Stop closed captions
3. Leave call
4. Cleanup event listeners
5. Navigate to home page

Edge Cases Handled:

Duplicate join attempts (ref pattern)

Network disconnections (Stream handles reconnection)

Browser refresh (re-authentication)

Token expiration (24-hour validity)

Complete User Journey

"Let me walk through the entire user experience:"

Minute 0:00 - Entry

User visits homepage

Sees clean, simple form


Enters name "Sarah" or leaves blank

Minute 0:05 - Authentication

Clicks "Join Meeting"

Sees loading spinner

System generates token in background

Token creation takes ~200ms

Minute 0:07 - Meeting Join

Meeting room loads

Video initializes

Sees own camera feed

Transcript panel ready

Minute 0:10 - Start Speaking

Sarah: "Hello everyone"

Transcript appears: "[Sarah]: Hello everyone"

Timestamp: "2:45:30 PM"

Minute 5:00 - Q&A

Sarah: "Hey Assistant, what have we discussed so far?"

Agent processes request

Generates summary from transcript

Speaks response in 3-4 seconds

Minute 30:00 - Leave

Sarah clicks "Leave"

Call disconnects gracefully

Returns to home page

Backend logs meeting summary


7. Challenges & Solutions (3-4 minutes)

Challenge 1: Token "Used Before Issued" Error

Problem:

Error: Token validation failed


Reason: iat (issued at) claim is in the future

Root Cause:

Clock skew between server and [Link] servers

Even 1-2 second difference causes rejection

JWT validation is strict about timestamps

Solution Attempts:

1. ❌ NTP sync (requires server access)


2. ❌ Longer validity (doesn't solve root cause)
3. ✅ Subtract 10 seconds from iat

Code:

javascript

const now = [Link]([Link]() / 1000);


const iatTime = now - 10; // THE FIX

const token = [Link]({


user_id: userId,
validity_in_seconds: 24 * 60 * 60,
iat: iatTime, // Use past time
} );

Why this works:

Token claims to be issued 10 seconds ago

Even if clocks differ by 5 seconds, still valid

Stream accepts tokens with iat in the past

No downsides (token still valid for full 24 hours)

Learning:
Always account for distributed system clock drift

JWT validation is strict

Small time offsets can break authentication

Challenge 2: React Strict Mode Double Mounting

Problem:

In development, React mounts components twice

Caused duplicate call joins

Multiple WebRTC connections

Transcript duplicates

Symptoms:

JOIN CALL
LEAVE CALL (cleanup)
JOIN CALL (again)

Solution: Ref Pattern

javascript

const joinedRef = useRef(false);

useEffect(() => {
if ([Link]) return; // Prevent double execution
[Link] = true;

// ... join call logic


}, [client, callId]);

Why refs work:

Refs persist across re-renders

Don't trigger re-renders when changed

Perfect for tracking "did this already" state

Alternative Solutions Tried:


1. ❌ State variable (causes infinite loop)
2. ❌ Disable Strict Mode (bad practice)
3. ✅ Ref flag

Challenge 3: Vision Agent Interrupting Conversations

Problem:

Initial agent responded to every question

Even rhetorical questions

Even questions directed at other participants

Made meetings awkward

Example of Bad Behavior:

User A: "What do you think about this idea?"


Agent: "I think it's a great approach because..."
User A: "I was asking User B... 😐"

Solution: Strict Behavioral Instructions

python

instructions="""
CRITICAL RULES - FOLLOW EXACTLY:
1. YOU MUST NEVER SPEAK unless someone says "Hey Assistant"
2. DO NOT respond to conversations between users
3. DO NOT acknowledge anything users say to each other
"""

Iterations Required:

Version 1: Agent spoke 80% of the time (too much)

Version 2: Agent asked if it should respond (annoying)

Version 3: Agent explained it was staying quiet (unnecessary)

Version 4: Silent until triggered ✅

Key Learning:
AI agents need VERY explicit behavioral rules

Default LLM behavior is too conversational

Negative instructions ("DON'T do X") are essential

Test with real conversations, not just scripts

Challenge 4: Chat Client Reconnection Issues

Problem:

On component remount, tried to reconnect chat client

StreamChat complained about duplicate connections

Console errors flooded logs

Sometimes caused authentication loops

Solution: Singleton Pattern

javascript

myChatClient = [Link](apiKey);

if (![Link]) {
await [Link](user, token);
}

How it works:

getInstance reuses existing connection

Only connect if userID is null

Prevents duplicate connection attempts

Cleanup Strategy:

javascript

return () => {
isMounted = false;
// DON'T disconnect on unmount
// Causes issues with reconnection
};
"Counter-intuitive but necessary:"

Usually you clean up in useEffect return

But here, disconnecting causes more problems

Stream clients should live for session duration

Challenge 5: Transcript Auto-Scroll

Problem:

New transcripts appeared but stayed off-screen

Users had to manually scroll

Poor UX for long meetings

Solution: Ref + ScrollIntoView

javascript

const transcriptEndRef = useRef(null);

useEffect(() => {
[Link]?.scrollIntoView({ behavior: "smooth" });
}, [transcripts]);

// In render:
{[Link](...)}
<div ref={transcriptEndRef} />

Why this works:

Invisible div at end of transcript list

Ref points to this div

When transcripts change, scroll to ref

behavior: "smooth" for nice animation

Alternative Approaches:

1. ❌ [Link] (scrolls entire page)


2. ❌ [Link] (not smooth)
3. ✅ scrollIntoView with smooth
Challenge 6: Environment Variable Management

Problem:

API keys needed in multiple places

Different keys for frontend vs backend

Risk of exposing secrets

Deployment configuration complexity

Solution: Structured .env Files

Frontend (.[Link]):

bash

# Public variables (exposed to browser)


NEXT_PUBLIC_STREAM_API_KEY=xyz
NEXT_PUBLIC_CALL_ID=meeting123

# Private variables (server-only)


STREAM_API_SECRET=secret123

Backend (.env):

bash

STREAM_API_KEY=xyz
STREAM_API_SECRET=secret123
CALL_ID=meeting123
GOOGLE_API_KEY=gemini_key

Best Practices:

1. Never commit .env files to Git

2. Use .[Link] with dummy values

3. Prefix public vars with NEXT_PUBLIC_

4. Keep secrets server-side only

5. Different keys for dev/staging/prod


Technical Debt & Future Improvements

Current Limitations:

1. Single Meeting ID
Currently hardcoded in environment

Should support dynamic meeting creation

2. No Persistence
Transcripts lost when agent stops

Should save to database

3. No User Authentication
Anyone with link can join

Should add password protection

4. Limited Chat Features

Chat client initialized but not used


Could add text messaging

5. No Recording

Can't replay meetings

Should add cloud recording

Planned Enhancements:

1. Meeting Management
Create meeting via UI
Schedule future meetings

Recurring meetings

2. Transcript Export

Download as PDF
Email summary

Integration with Google Docs

3. Advanced AI Features
Action item extraction

Sentiment analysis
Speaker identification
Multi-language support

4. Analytics Dashboard

Meeting duration
Participant engagement

Speaking time distribution


Keyword extraction

8. Q&A Preparation

Technical Questions

Q: Why [Link] instead of building WebRTC yourself?

A: "[Link] provides production-ready infrastructure that would take months to build:

TURN/STUN servers for NAT traversal

Scalable media servers

Built-in transcription

Mobile SDKs

99.99% uptime SLA

Building this from scratch would require:

DevOps expertise

Significant infrastructure costs

Ongoing maintenance

Security audits

For a project like this, [Link]'s free tier is perfect and lets me focus on the AI features rather than low-level
video infrastructure."

Q: How does the transcription work technically?

A: "[Link] uses their own speech-to-text engine that:

1. Receives audio from participants via WebRTC

2. Processes in real-time on their servers


3. Generates closed caption events

4. Sends via WebSocket to all connected clients

The events look like:

javascript

{
type: 'call.closed_caption',
closed_caption: {
text: 'Hello everyone',
user: { id: 'user123', name: 'John' },
start_time: '2024-01-11T12:30:45Z'
}
}

Both the frontend TranscriptPanel and backend Vision Agent subscribe to these events, so they both have the
same transcript data."

Q: What happens if the Python agent crashes?

A: "Great question. Currently:

Frontend continues to work normally

Users can still have video calls

Transcription still works in UI

Only Q&A feature breaks

Improvements needed:

1. Automatic agent restart

2. Health check endpoint

3. Fallback error message in UI

4. Alert to administrator

Production solution:

Run agent in container (Docker/Kubernetes)

Restart policy: always

Monitoring with Prometheus


Auto-scaling for multiple meetings"

Q: How do you handle multiple simultaneous meetings?

A: "Currently, the system supports one meeting (hardcoded call ID). For multiple meetings:

Architecture changes needed:

1. Meeting Management Service

Create meeting API endpoint


Generate unique call IDs

Store meeting metadata

2. Agent Pool
Multiple Python agents running

Each handles one meeting


Dynamic agent assignment

3. Frontend Changes
Meeting creation UI
Meeting list/dashboard

Join via unique link

Code example for dynamic meetings:

javascript

// Create meeting
POST /api/meetings
Response: { meetingId: 'abc123', joinUrl: '/meeting/abc123' }

// Python agent
call_id = [Link]('CALL_ID') # From agent startup args

Scalability:

1 agent per meeting

Agents can run on different machines

Load balancer distributes agents

Horizontal scaling as needed"


Q: Why [Link] instead of plain React or Vite?

A: "[Link] provides several advantages:

1. API Routes: Backend endpoint in same codebase

2. File-based Routing: No react-router configuration

3. Server-Side Rendering: Better initial load (though not critical here)

4. Environment Variables: Built-in support with NEXT_PUBLIC_ prefix

5. Production Ready: Optimized builds out of the box

6. Deployment: Vercel one-click deploy

For this project specifically:

API route for token generation is essential

Dynamic routing for /meeting/[id]

Environment variable management

Professional developer experience

Alternatives considered:

Vite + Express: More setup, separate server

Create React App: Deprecated, no backend

Plain React: Would need separate backend anyway"

Q: How secure is the authentication?

A: "The authentication follows JWT best practices:

Security measures:

1. API Secret Never Exposed

Only exists in backend


Not in frontend code

Not in browser

2. Short-Lived Tokens
24-hour validity
Can reduce for higher security

Automatic expiration

3. User-Specific Tokens

Each user gets unique token


Token tied to user ID
Can't be reused by others

4. HTTPS in Production
Encrypted transmission

No token interception

Potential improvements:

1. Token Refresh: Issue new tokens before expiry

2. Rate Limiting: Prevent token generation spam

3. IP Whitelisting: Restrict token generation to known IPs

4. Meeting Passwords: Add extra auth layer

5. OAuth Integration: Google/GitHub login

Current risk assessment:

Low risk for demo/internal use

Medium risk for public deployment

High risk for sensitive meetings

For production:

Add meeting passwords

Implement user authentication (OAuth)

Add audit logging

Regular security audits"

Q: What's the latency like?

A: "Latency breakdown:
Video Transmission:

WebRTC: 100-300ms (excellent for real-time)

No perceptible delay in conversation

Transcription:

Speech-to-text processing: 500-1000ms

Acceptable for transcript display

Not suitable for real-time subtitles

AI Response:

Gemini processing: 2-4 seconds

Acceptable for Q&A use case

Much faster than GPT-4 (5-8 seconds)

Total Q&A Latency:

User says "Hey Assistant" → Transcription (1s)


→ Agent receives event (0.1s)
→ Build context (0.1s)
→ Gemini processes (2-3s)
→ Agent speaks response (0.5s)
= ~4-5 seconds total

Optimization opportunities:

1. Streaming Responses: Start speaking before full answer generated

2. Context Caching: Pre-build context between questions

3. Faster Model: Use Gemini Flash instead of Pro

4. Edge Deployment: Run agent closer to users"

Business/Product Questions

Q: Who is the target audience?

A: "Primary target audiences:

1. Remote Teams
Daily standups
Planning meetings

Retrospectives

2. Educational Institutions

Online classes
Student group projects
Office hours

3. Healthcare
Telemedicine consultations

Medical transcription
Patient notes

4. Legal

Client consultations
Depositions

Case discussions

Key value propositions:

Automatic transcription saves manual note-taking

AI assistant can answer questions without interrupting meeting

Search through past meetings

Action item extraction"

Q: How would you monetize this?

A: "Potential business models:

Freemium Tier:

5 meetings/month

30-minute max duration

Basic transcription

24-hour transcript retention

Pro Tier ($10/month):


Unlimited meetings

No duration limit

Advanced AI features

1-year transcript retention

Export to PDF/Docs

Business Tier ($50/month):

All Pro features

Custom AI training on company data

Integrations (Slack, Teams, Google Workspace)

Admin dashboard

SSO authentication

Priority support

Enterprise Tier (Custom):

Self-hosted option

Unlimited users

Custom features

SLA guarantees

Dedicated support

Additional Revenue Streams:

API access for developers

White-label solution

Per-minute transcription pricing

Custom AI model training"

Q: What are the main competitors?

A: "Competitive landscape:

Direct Competitors:
1. [Link]
Pros: Established, accurate transcription

Cons: No video, expensive, limited AI

2. [Link]

Pros: Good integrations, CRM features


Cons: Complex UI, privacy concerns

3. Grain

Pros: Video clips, good UX


Cons: Focused on sales, expensive

Our Differentiators:

1. Real-time Q&A: Unique AI assistant feature

2. Open Source Potential: Could offer self-hosted version

3. Simpler UX: Just join and talk

4. Custom AI: Can train on company data

5. Price: More affordable for small teams

Indirect Competitors:

Zoom (basic transcription)

Google Meet (auto-captions)

Microsoft Teams (transcription)

Competitive Advantages:

More powerful AI features

Better user experience

Lower cost

Privacy-focused (self-hosted option)"

Implementation Questions

Q: How long did this take to build?

A: "Development timeline:
Week 1: Planning & Setup (10 hours)

Architecture design

Technology research

[Link] account setup

Boilerplate code

Week 2: Frontend Core (15 hours)

[Link] setup

Homepage & routing

Stream integration

Basic video calling

Week 3: Transcription (12 hours)

Transcript panel UI

Event handling

Auto-scroll feature

UI polish

Week 4: Backend Agent (20 hours)

Python environment setup

Vision Agents learning curve

Gemini integration

Q&A system

Behavioral prompt engineering

Week 5: Bug Fixes & Polish (10 hours)

Token clock skew fix

React Strict Mode issues

UI improvements

Documentation

Total: ~70 hours


Time breakdown:

Frontend: 40%

Backend: 30%

Bug fixing: 20%

Documentation: 10%

Longest challenges:

Token authentication issues: 8 hours

Agent behavioral tuning: 6 hours

React remounting bugs: 4 hours"

Q: What would you do differently if starting over?

A: "Key lessons learned:

Technical Decisions:

1. Start with simpler AI


Should've used basic chat API first

Vision Agents learning curve was steep


Could've validated concept faster

2. Add database from day one


Transcript persistence is essential
Should've used Prisma + PostgreSQL

Would enable more features

3. Better error handling

Need more graceful degradation


Should catch all async errors
Better user error messages

4. Automated testing
Integration tests for call flow

Mock [Link] in tests


E2E tests with Playwright
Process Improvements:

1. Design phase

Should've created Figma mockups


User flow diagrams first

Would've saved refactoring time

2. Incremental deployment
Should've deployed MVP earlier

Get user feedback sooner


Iterate based on real usage

3. Documentation
Should've documented as I built
Architecture decisions

API contracts

But overall:

Project was successful

Learned many new technologies

Built something functional and impressive

Good foundation for future features"

Q: How would you scale this to 100,000 users?

A: "Scaling strategy:

Infrastructure:

1. Frontend
CDN for static assets (Cloudflare)

Edge caching for API routes


Deploy to Vercel (auto-scaling)

2. Backend API
Separate [Link] server
Load balancer (AWS ALB)
Auto-scaling groups
Rate limiting (Redis)

3. Python Agents
Container orchestration (Kubernetes)
Agent pool management

Horizontal scaling
Health checks & auto-restart

4. Database
PostgreSQL with read replicas
Meeting metadata

User accounts
Transcript storage

5. Message Queue
RabbitMQ or SQS
Decouple agent assignment

Handle burst traffic

Cost Estimation:

100,000 users
Average 2 meetings/month per user
Average 30 minutes per meeting

= 200,000 meetings/month
= 100,000 hours/month

[Link]: ~$0.005/minute = $30,000/month


Gemini API: ~$0.10/1K tokens = $10,000/month
Infrastructure: $5,000/month
Total: ~$45,000/month

Revenue needed: $50,000+/month


Price point: $10/month
Conversion rate: 5%
= Need 100,000 * 5% = 5,000 paying users

Architecture diagram:
[Cloudflare CDN]

[Load Balancer]

┌──────────────────┴──────────────────┐
↓ ↓
[[Link] Cluster] [API Server Cluster]
↓ ↓
└──────────────────┬──────────────────┘

[Message Queue]

[Agent Pool Manager]

┌──────────────────┼──────────────────┐
↓ ↓ ↓
[Agent Pod 1] [Agent Pod 2] [Agent Pod N]
└──────────────────┴───────────────────┘

[PostgreSQL]
```"

---

## Conclusion & Future Vision (2 minutes)

**"To summarize:"**

### What We Built


- **Full-stack video calling platform** with AI assistance
- **Real-time transcription** with professional UI
- **Context-aware Q&A system** using Gemini AI
- **Production-ready architecture** with scalability in mind

### Technical Achievements


- Integrated 4 major technologies ([Link], [Link], Vision Agents, Gemini)
- Solved complex real-time synchronization challenges
- Built responsive, beautiful UI
- Implemented secure authentication

### Learning Outcomes


- WebRTC and real-time communication
- AI agent behavioral design
- Async event-driven architecture
- Production deployment considerations
### Future Vision
**"This project is just the beginning. I envision it evolving into:"**

1. **Meeting Intelligence Platform**


- Automatic action item extraction
- Sentiment analysis
- Speaking time analytics
- Meeting effectiveness scores

2. **Team Productivity Suite**


- Calendar integration
- Slack/Teams notifications
- CRM integration
- Custom AI training on company data

3. **Enterprise Solution**
- Self-hosted option for security
- SSO integration
- Compliance features (HIPAA, GDPR)
- Advanced admin controls

4. **AI-Powered Insights**
- Meeting summary emails
- Trend analysis across meetings
- Predictive scheduling
- Participant engagement tracking

**"Thank you for your time. I'm happy to answer any questions or dive deeper into any technical aspect you'd like to
explore further!"**

---

## Appendix: Quick Reference

### Key Technologies


- **Frontend**: [Link] 14, React 18, Tailwind CSS
- **Backend**: [Link] (API), Python 3.x (Agent)
- **Video**: [Link] Video SDK
- **AI**: Google Gemini Realtime API
- **Framework**: Vision Agents

### Repository Structure


```
project/
├── app/
│ ├── api/
│ │ └── token/
│ │ └── [Link] (Token generation API)
│ ├── components/
│ │ ├── [Link] (Main meeting interface)
│ │ ├── [Link] (Stream context provider)
│ │ └── [Link] (Live transcript panel)
│ ├── hooks/
│ │ └── [Link] (Client initialization)
│ ├── meeting/
│ │ └── [id]/
│ │ └── [Link] (Dynamic meeting page)
│ └── [Link] (Home page)
├── backend/
│ ├── [Link] (Vision Agent)
│ ├── .env (Backend config)
│ └── [Link] (Python dependencies)
└── .[Link] (Frontend config)

Environment Variables Reference

bash

# Frontend
NEXT_PUBLIC_STREAM_API_KEY=your_key
NEXT_PUBLIC_CALL_ID=meeting_id
STREAM_API_SECRET=your_secret

# Backend
STREAM_API_KEY=your_key
STREAM_API_SECRET=your_secret
CALL_ID=meeting_id
GOOGLE_API_KEY=gemini_key

Key API Endpoints

POST /api/token - Generate Stream authentication token

Useful Commands

bash
# Frontend
npm run dev # Start development server
npm run build # Production build
npm start # Start production server

# Backend
python [Link] # Start Vision Agent
pip install -r [Link] # Install dependencies

Important Links

[Link] Docs: [Link]

Vision Agents: [Link]

Gemini API: [Link]

END OF PRESENTATION GUIDE

Total estimated presentation time: 30-35 minutes Adjust pacing based on audience engagement and questions

You might also like