From 0af91c6dd7aeb2fade3ae98e039b9c65f9755f0d Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 27 Mar 2025 14:41:25 +0000
Subject: [PATCH 1/2] Add Codegen Google Meet + Zoom Bot proof-of-concept
examples
---
examples/meeting_bot/README.md | 91 ++++++
examples/meeting_bot/recall_ai_poc.py | 245 +++++++++++++++
examples/meeting_bot/zoom_sdk_poc.js | 427 ++++++++++++++++++++++++++
3 files changed, 763 insertions(+)
create mode 100644 examples/meeting_bot/README.md
create mode 100644 examples/meeting_bot/recall_ai_poc.py
create mode 100644 examples/meeting_bot/zoom_sdk_poc.js
diff --git a/examples/meeting_bot/README.md b/examples/meeting_bot/README.md
new file mode 100644
index 000000000..b2ad216e2
--- /dev/null
+++ b/examples/meeting_bot/README.md
@@ -0,0 +1,91 @@
+# Codegen Meeting Bot Examples
+
+This directory contains proof-of-concept examples for implementing a Codegen bot that can join Google Meet and Zoom meetings.
+
+## Overview
+
+The Codegen Meeting Bot is designed to:
+
+1. Join video meetings on platforms like Google Meet and Zoom
+2. Record and transcribe meetings
+3. Answer questions about Codegen during meetings
+4. Generate meeting summaries and action items
+
+## Implementation Options
+
+### 1. Recall.ai Integration (recall_ai_poc.py)
+
+This example demonstrates how to use the [Recall.ai](https://www.recall.ai/) API to create a meeting bot that works across multiple platforms.
+
+**Features:**
+- Platform-agnostic implementation (works with Google Meet, Zoom, MS Teams, etc.)
+- Real-time transcription streaming
+- Meeting recording and processing
+- Customizable bot name and appearance
+
+**Requirements:**
+- Python 3.8+
+- Recall.ai API key
+- Required packages: `requests`, `asyncio`, `websockets`
+
+**Usage:**
+```python
+# Set your Recall.ai API key
+export RECALL_API_KEY="your_api_key_here"
+
+# Run the example
+python recall_ai_poc.py
+```
+
+### 2. Zoom SDK Integration (zoom_sdk_poc.js)
+
+This example demonstrates how to use the Zoom Meeting SDK to create a bot specifically for Zoom meetings.
+
+**Features:**
+- Join Zoom meetings programmatically
+- Listen to meeting events (chat messages, participant changes, etc.)
+- Respond to questions in the chat
+- Customizable bot behavior
+
+**Requirements:**
+- Node.js
+- Zoom Meeting SDK credentials
+- Required packages: `puppeteer`, `express`, `body-parser`, `crypto`, `cors`
+
+**Usage:**
+```javascript
+// Set your Zoom SDK credentials
+export ZOOM_SDK_KEY="your_sdk_key_here"
+export ZOOM_SDK_SECRET="your_sdk_secret_here"
+
+// Install dependencies
+npm install puppeteer express body-parser crypto cors
+
+// Run the example
+node zoom_sdk_poc.js
+```
+
+## Integration with Codegen
+
+To fully integrate these examples with Codegen, you would need to:
+
+1. Connect to the Codegen API to process questions and generate responses
+2. Implement a calendar integration to automatically schedule bots for meetings
+3. Create a user interface for managing bot settings and viewing meeting summaries
+4. Set up secure storage for meeting recordings and transcripts
+
+## Next Steps
+
+These examples are proof-of-concept implementations and not production-ready. For a production implementation, consider:
+
+1. Error handling and retry logic
+2. Authentication and security
+3. Scalability for multiple concurrent meetings
+4. Proper logging and monitoring
+5. User management and permissions
+
+## Resources
+
+- [Recall.ai Documentation](https://docs.recall.ai/docs/getting-started)
+- [Zoom Meeting SDK Documentation](https://marketplace.zoom.us/docs/sdk/native-sdks/web/)
+- [Google Meet Bot Examples](https://github.com/Ritika-Das/Google-Meet-Bot)
\ No newline at end of file
diff --git a/examples/meeting_bot/recall_ai_poc.py b/examples/meeting_bot/recall_ai_poc.py
new file mode 100644
index 000000000..901fdebba
--- /dev/null
+++ b/examples/meeting_bot/recall_ai_poc.py
@@ -0,0 +1,245 @@
+"""
+Codegen Meeting Bot - Recall.ai Proof of Concept
+
+This script demonstrates how to use Recall.ai to create a meeting bot that can:
+1. Join a Google Meet or Zoom meeting
+2. Record the meeting
+3. Generate a transcript
+4. Process the transcript with Codegen
+
+Requirements:
+- Recall.ai API key
+- Python 3.8+
+- Required packages: requests, asyncio, websockets
+
+Note: This is a proof-of-concept and not production-ready code.
+"""
+
+import os
+import json
+import time
+import asyncio
+import requests
+from typing import Dict, Any, Optional, List
+
+# Configuration
+RECALL_API_KEY = os.environ.get("RECALL_API_KEY", "your_api_key_here")
+RECALL_API_BASE_URL = "https://api.recall.ai/api/v1"
+
+class CodegenMeetingBot:
+ """A meeting bot that uses Recall.ai to join meetings and process transcripts with Codegen."""
+
+ def __init__(self, api_key: str):
+ """Initialize the meeting bot with the Recall.ai API key."""
+ self.api_key = api_key
+ self.headers = {
+ "Authorization": f"Token {self.api_key}",
+ "Content-Type": "application/json"
+ }
+
+ def create_bot(self,
+ platform: str,
+ meeting_url: str,
+ bot_name: str = "Codegen Assistant",
+ join_at: Optional[str] = None) -> Dict[str, Any]:
+ """
+ Create a bot to join a meeting.
+
+ Args:
+ platform: The meeting platform ("zoom", "google_meet", "ms_teams", etc.)
+ meeting_url: The URL of the meeting to join
+ bot_name: The display name for the bot
+ join_at: ISO 8601 timestamp for when the bot should join (None for immediate)
+
+ Returns:
+ The bot data from the Recall.ai API
+ """
+ endpoint = f"{RECALL_API_BASE_URL}/bot/"
+
+ payload = {
+ "meeting_url": meeting_url,
+ "platform": platform,
+ "bot_name": bot_name
+ }
+
+ if join_at:
+ payload["join_at"] = join_at
+
+ response = requests.post(endpoint, headers=self.headers, json=payload)
+ response.raise_for_status()
+
+ return response.json()
+
+ def get_bot(self, bot_id: str) -> Dict[str, Any]:
+ """
+ Get information about a bot.
+
+ Args:
+ bot_id: The ID of the bot
+
+ Returns:
+ The bot data from the Recall.ai API
+ """
+ endpoint = f"{RECALL_API_BASE_URL}/bot/{bot_id}/"
+
+ response = requests.get(endpoint, headers=self.headers)
+ response.raise_for_status()
+
+ return response.json()
+
+ def list_bots(self, limit: int = 10) -> List[Dict[str, Any]]:
+ """
+ List all bots.
+
+ Args:
+ limit: Maximum number of bots to return
+
+ Returns:
+ List of bot data from the Recall.ai API
+ """
+ endpoint = f"{RECALL_API_BASE_URL}/bot/?limit={limit}"
+
+ response = requests.get(endpoint, headers=self.headers)
+ response.raise_for_status()
+
+ return response.json().get("results", [])
+
+ async def stream_transcription(self, bot_id: str):
+ """
+ Stream real-time transcription from a bot.
+
+ Args:
+ bot_id: The ID of the bot
+ """
+ import websockets
+
+ # Get the bot data to check if it's active
+ bot = self.get_bot(bot_id)
+
+ if bot.get("status") != "joined":
+ print(f"Bot is not active in the meeting. Current status: {bot.get('status')}")
+ return
+
+ # Connect to the transcription websocket
+ ws_url = f"wss://api.recall.ai/ws/bot/{bot_id}/transcription/"
+
+ async with websockets.connect(ws_url, extra_headers={"Authorization": f"Token {self.api_key}"}) as websocket:
+ print("Connected to transcription stream. Waiting for transcription...")
+
+ while True:
+ try:
+ message = await websocket.recv()
+ data = json.loads(message)
+
+ if data.get("event") == "transcript_part":
+ speaker = data.get("speaker", "Unknown")
+ text = data.get("text", "")
+ print(f"{speaker}: {text}")
+
+ # Here you would process the transcript with Codegen
+ # For example, detect if someone is asking a question about Codegen
+ if "codegen" in text.lower() and "?" in text:
+ print("Detected question about Codegen!")
+ # In a real implementation, you would:
+ # 1. Process the question with Codegen
+ # 2. Generate a response
+ # 3. Send the response back to the meeting (via chat or audio)
+
+ except Exception as e:
+ print(f"Error in transcription stream: {e}")
+ break
+
+ def process_meeting_recording(self, bot_id: str) -> Dict[str, Any]:
+ """
+ Process a completed meeting recording.
+
+ Args:
+ bot_id: The ID of the bot
+
+ Returns:
+ Processed meeting data
+ """
+ # Get the bot data
+ bot = self.get_bot(bot_id)
+
+ if bot.get("status") not in ["left", "ended"]:
+ print(f"Meeting is not completed yet. Current status: {bot.get('status')}")
+ return {}
+
+ # Get the recording URL
+ recording_url = bot.get("video_url")
+
+ if not recording_url:
+ print("No recording available for this meeting.")
+ return {}
+
+ print(f"Recording available at: {recording_url}")
+
+ # In a real implementation, you would:
+ # 1. Download the recording
+ # 2. Process the full transcript
+ # 3. Generate a meeting summary with Codegen
+ # 4. Extract action items
+ # 5. Store the results
+
+ return {
+ "meeting_id": bot.get("id"),
+ "duration": bot.get("duration"),
+ "recording_url": recording_url,
+ "platform": bot.get("platform"),
+ "summary": "This is where the meeting summary would go.",
+ "action_items": ["Action item 1", "Action item 2"]
+ }
+
+
+async def main():
+ """Main function to demonstrate the Codegen Meeting Bot."""
+ # Initialize the bot
+ bot = CodegenMeetingBot(RECALL_API_KEY)
+
+ # Example: Create a bot to join a Google Meet meeting
+ meeting_url = "https://meet.google.com/abc-defg-hij"
+
+ try:
+ # Create a bot to join the meeting
+ print(f"Creating bot to join meeting: {meeting_url}")
+ bot_data = bot.create_bot(
+ platform="google_meet",
+ meeting_url=meeting_url,
+ bot_name="Codegen Assistant"
+ )
+
+ bot_id = bot_data.get("id")
+ print(f"Bot created with ID: {bot_id}")
+ print(f"Bot status: {bot_data.get('status')}")
+
+ # Wait for the bot to join the meeting
+ print("Waiting for bot to join the meeting...")
+ for _ in range(30): # Wait up to 30 seconds
+ bot_data = bot.get_bot(bot_id)
+ if bot_data.get("status") == "joined":
+ print("Bot has joined the meeting!")
+ break
+ time.sleep(1)
+
+ # Stream transcription in real-time
+ print("Starting transcription stream...")
+ await bot.stream_transcription(bot_id)
+
+ # In a real implementation, you would wait for the meeting to end
+ # For this example, we'll just wait a few seconds
+ print("Simulating meeting duration (10 seconds)...")
+ time.sleep(10)
+
+ # Process the meeting recording
+ print("Processing meeting recording...")
+ meeting_data = bot.process_meeting_recording(bot_id)
+ print(f"Meeting data: {json.dumps(meeting_data, indent=2)}")
+
+ except Exception as e:
+ print(f"Error: {e}")
+
+
+if __name__ == "__main__":
+ # Run the main function
+ asyncio.run(main())
\ No newline at end of file
diff --git a/examples/meeting_bot/zoom_sdk_poc.js b/examples/meeting_bot/zoom_sdk_poc.js
new file mode 100644
index 000000000..b1473c77d
--- /dev/null
+++ b/examples/meeting_bot/zoom_sdk_poc.js
@@ -0,0 +1,427 @@
+/**
+ * Codegen Meeting Bot - Zoom SDK Proof of Concept
+ *
+ * This script demonstrates how to use the Zoom Meeting SDK to create a meeting bot that can:
+ * 1. Join a Zoom meeting
+ * 2. Listen to meeting events
+ * 3. Interact with the meeting
+ *
+ * Requirements:
+ * - Node.js
+ * - Zoom Meeting SDK credentials
+ * - Puppeteer for headless browser automation
+ *
+ * Note: This is a proof-of-concept and not production-ready code.
+ */
+
+const puppeteer = require('puppeteer');
+const express = require('express');
+const bodyParser = require('body-parser');
+const crypto = require('crypto');
+const cors = require('cors');
+const path = require('path');
+const fs = require('fs');
+
+// Configuration
+const PORT = process.env.PORT || 3000;
+const ZOOM_SDK_KEY = process.env.ZOOM_SDK_KEY || 'your_sdk_key_here';
+const ZOOM_SDK_SECRET = process.env.ZOOM_SDK_SECRET || 'your_sdk_secret_here';
+
+// Express app setup
+const app = express();
+app.use(cors());
+app.use(bodyParser.json());
+app.use(express.static('public'));
+
+// Generate a Zoom Meeting SDK JWT token
+function generateZoomToken(sdkKey, sdkSecret, meetingNumber, role) {
+ const iat = Math.round(new Date().getTime() / 1000) - 30;
+ const exp = iat + 60 * 60 * 2; // Token expires in 2 hours
+ const oHeader = { alg: 'HS256', typ: 'JWT' };
+
+ const oPayload = {
+ sdkKey: sdkKey,
+ mn: meetingNumber,
+ role: role,
+ iat: iat,
+ exp: exp,
+ tokenExp: exp
+ };
+
+ const sHeader = JSON.stringify(oHeader);
+ const sPayload = JSON.stringify(oPayload);
+ const signature = crypto.createHmac('sha256', sdkSecret)
+ .update(Buffer.from(sHeader + "." + sPayload).toString('base64'))
+ .digest('base64');
+
+ return Buffer.from(sHeader).toString('base64') + "." +
+ Buffer.from(sPayload).toString('base64') + "." +
+ signature;
+}
+
+// API endpoint to generate a token
+app.post('/api/token', (req, res) => {
+ const { meetingNumber, role } = req.body;
+
+ if (!meetingNumber) {
+ return res.status(400).json({ error: 'Meeting number is required' });
+ }
+
+ const token = generateZoomToken(ZOOM_SDK_KEY, ZOOM_SDK_SECRET, meetingNumber, role || 0);
+ res.json({ token });
+});
+
+// HTML template for the Zoom client
+const zoomClientHtml = `
+
+
+
+ Codegen Zoom Bot
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+// Serve the Zoom client HTML
+app.get('/zoom-client', (req, res) => {
+ res.send(zoomClientHtml);
+});
+
+// Start the server
+app.listen(PORT, () => {
+ console.log(`Server running on port ${PORT}`);
+});
+
+/**
+ * CodegenZoomBot class for controlling a Zoom meeting bot
+ */
+class CodegenZoomBot {
+ constructor() {
+ this.browser = null;
+ this.page = null;
+ this.serverUrl = `http://localhost:${PORT}`;
+ this.isConnected = false;
+ this.meetingData = {
+ meetingNumber: '',
+ password: '',
+ userName: 'Codegen Assistant',
+ };
+ }
+
+ /**
+ * Initialize the bot
+ */
+ async initialize() {
+ // Launch a headless browser
+ this.browser = await puppeteer.launch({
+ headless: true,
+ args: [
+ '--no-sandbox',
+ '--disable-setuid-sandbox',
+ '--disable-web-security',
+ '--allow-running-insecure-content',
+ '--use-fake-ui-for-media-stream',
+ '--use-fake-device-for-media-stream',
+ ],
+ });
+
+ // Create a new page
+ this.page = await this.browser.newPage();
+
+ // Set up event listeners for messages from the Zoom client
+ await this.page.exposeFunction('onClientMessage', (message) => {
+ const { type, data } = message;
+
+ switch (type) {
+ case 'CLIENT_READY':
+ console.log('Zoom client is ready');
+ break;
+ case 'JOIN_SUCCESS':
+ console.log('Successfully joined the meeting');
+ this.isConnected = true;
+ break;
+ case 'JOIN_ERROR':
+ console.error('Failed to join the meeting:', data);
+ break;
+ case 'CONNECTION_CHANGE':
+ console.log('Connection changed:', data);
+ break;
+ case 'AUDIO_CHANGE':
+ console.log('Audio changed:', data);
+ break;
+ case 'CHAT_RECEIVED':
+ console.log('Chat received:', data);
+ this.processChat(data);
+ break;
+ default:
+ console.log('Unknown message type:', type);
+ }
+ });
+
+ // Set up message listener
+ await this.page.evaluateOnNewDocument(() => {
+ window.addEventListener('message', (event) => {
+ window.onClientMessage(event.data);
+ });
+ });
+
+ // Navigate to the Zoom client page
+ await this.page.goto(`${this.serverUrl}/zoom-client`);
+
+ console.log('Bot initialized');
+ }
+
+ /**
+ * Join a Zoom meeting
+ * @param {string} meetingNumber - The Zoom meeting number
+ * @param {string} password - The Zoom meeting password
+ */
+ async joinMeeting(meetingNumber, password) {
+ this.meetingData.meetingNumber = meetingNumber;
+ this.meetingData.password = password;
+
+ // Get a token for the meeting
+ const response = await fetch(`${this.serverUrl}/api/token`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ meetingNumber,
+ role: 0, // 0 for attendee, 1 for host
+ }),
+ });
+
+ const { token } = await response.json();
+
+ // Send a message to the Zoom client to join the meeting
+ await this.page.evaluate((data) => {
+ window.postMessage({
+ type: 'JOIN_MEETING',
+ data: {
+ meetingNumber: data.meetingNumber,
+ token: data.token,
+ userName: data.userName,
+ password: data.password,
+ },
+ }, '*');
+ }, {
+ meetingNumber,
+ token,
+ userName: this.meetingData.userName,
+ password,
+ });
+
+ console.log(`Joining meeting: ${meetingNumber}`);
+ }
+
+ /**
+ * Leave the current Zoom meeting
+ */
+ async leaveMeeting() {
+ if (!this.isConnected) {
+ console.log('Not connected to a meeting');
+ return;
+ }
+
+ // Send a message to the Zoom client to leave the meeting
+ await this.page.evaluate(() => {
+ window.postMessage({
+ type: 'LEAVE_MEETING',
+ }, '*');
+ });
+
+ this.isConnected = false;
+ console.log('Left the meeting');
+ }
+
+ /**
+ * Process a chat message from the meeting
+ * @param {Object} chatData - The chat message data
+ */
+ async processChat(chatData) {
+ const { message, sender } = chatData;
+
+ // Check if the message is directed to Codegen
+ if (message.toLowerCase().includes('codegen') && message.includes('?')) {
+ console.log(`Processing question from ${sender}: ${message}`);
+
+ // In a real implementation, you would:
+ // 1. Process the question with Codegen
+ // 2. Generate a response
+ // 3. Send the response back to the chat
+
+ // For this example, we'll just send a hardcoded response
+ await this.sendChatMessage(`Hello ${sender}, I'm the Codegen Assistant. I'm here to help with your Codegen questions!`);
+ }
+ }
+
+ /**
+ * Send a chat message to the meeting
+ * @param {string} message - The message to send
+ */
+ async sendChatMessage(message) {
+ if (!this.isConnected) {
+ console.log('Not connected to a meeting');
+ return;
+ }
+
+ // In a real implementation, you would use the Zoom SDK to send a chat message
+ // For this example, we'll just log the message
+ console.log(`Sending chat message: ${message}`);
+ }
+
+ /**
+ * Close the bot
+ */
+ async close() {
+ if (this.isConnected) {
+ await this.leaveMeeting();
+ }
+
+ if (this.browser) {
+ await this.browser.close();
+ }
+
+ console.log('Bot closed');
+ }
+}
+
+/**
+ * Example usage
+ */
+async function main() {
+ const bot = new CodegenZoomBot();
+
+ try {
+ // Initialize the bot
+ await bot.initialize();
+
+ // Join a meeting
+ const meetingNumber = '123456789';
+ const password = 'password';
+ await bot.joinMeeting(meetingNumber, password);
+
+ // Keep the bot running for a while
+ console.log('Bot is running. Press Ctrl+C to exit.');
+
+ // Handle process termination
+ process.on('SIGINT', async () => {
+ console.log('Shutting down...');
+ await bot.close();
+ process.exit(0);
+ });
+
+ } catch (error) {
+ console.error('Error:', error);
+ await bot.close();
+ }
+}
+
+// Run the example if this script is executed directly
+if (require.main === module) {
+ main();
+}
+
+module.exports = CodegenZoomBot;
\ No newline at end of file
From 148538f18ac5cd188130946d47d75179855f001c Mon Sep 17 00:00:00 2001
From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com>
Date: Thu, 27 Mar 2025 14:42:15 +0000
Subject: [PATCH 2/2] Automated pre-commit update
---
examples/meeting_bot/README.md | 28 +-
examples/meeting_bot/recall_ai_poc.py | 149 +++----
examples/meeting_bot/zoom_sdk_poc.js | 562 +++++++++++++-------------
3 files changed, 373 insertions(+), 366 deletions(-)
diff --git a/examples/meeting_bot/README.md b/examples/meeting_bot/README.md
index b2ad216e2..ec93cdb1f 100644
--- a/examples/meeting_bot/README.md
+++ b/examples/meeting_bot/README.md
@@ -7,9 +7,9 @@ This directory contains proof-of-concept examples for implementing a Codegen bot
The Codegen Meeting Bot is designed to:
1. Join video meetings on platforms like Google Meet and Zoom
-2. Record and transcribe meetings
-3. Answer questions about Codegen during meetings
-4. Generate meeting summaries and action items
+1. Record and transcribe meetings
+1. Answer questions about Codegen during meetings
+1. Generate meeting summaries and action items
## Implementation Options
@@ -18,17 +18,20 @@ The Codegen Meeting Bot is designed to:
This example demonstrates how to use the [Recall.ai](https://www.recall.ai/) API to create a meeting bot that works across multiple platforms.
**Features:**
+
- Platform-agnostic implementation (works with Google Meet, Zoom, MS Teams, etc.)
- Real-time transcription streaming
- Meeting recording and processing
- Customizable bot name and appearance
**Requirements:**
+
- Python 3.8+
- Recall.ai API key
- Required packages: `requests`, `asyncio`, `websockets`
**Usage:**
+
```python
# Set your Recall.ai API key
export RECALL_API_KEY="your_api_key_here"
@@ -42,17 +45,20 @@ python recall_ai_poc.py
This example demonstrates how to use the Zoom Meeting SDK to create a bot specifically for Zoom meetings.
**Features:**
+
- Join Zoom meetings programmatically
- Listen to meeting events (chat messages, participant changes, etc.)
- Respond to questions in the chat
- Customizable bot behavior
**Requirements:**
+
- Node.js
- Zoom Meeting SDK credentials
- Required packages: `puppeteer`, `express`, `body-parser`, `crypto`, `cors`
**Usage:**
+
```javascript
// Set your Zoom SDK credentials
export ZOOM_SDK_KEY="your_sdk_key_here"
@@ -70,22 +76,22 @@ node zoom_sdk_poc.js
To fully integrate these examples with Codegen, you would need to:
1. Connect to the Codegen API to process questions and generate responses
-2. Implement a calendar integration to automatically schedule bots for meetings
-3. Create a user interface for managing bot settings and viewing meeting summaries
-4. Set up secure storage for meeting recordings and transcripts
+1. Implement a calendar integration to automatically schedule bots for meetings
+1. Create a user interface for managing bot settings and viewing meeting summaries
+1. Set up secure storage for meeting recordings and transcripts
## Next Steps
These examples are proof-of-concept implementations and not production-ready. For a production implementation, consider:
1. Error handling and retry logic
-2. Authentication and security
-3. Scalability for multiple concurrent meetings
-4. Proper logging and monitoring
-5. User management and permissions
+1. Authentication and security
+1. Scalability for multiple concurrent meetings
+1. Proper logging and monitoring
+1. User management and permissions
## Resources
- [Recall.ai Documentation](https://docs.recall.ai/docs/getting-started)
- [Zoom Meeting SDK Documentation](https://marketplace.zoom.us/docs/sdk/native-sdks/web/)
-- [Google Meet Bot Examples](https://github.com/Ritika-Das/Google-Meet-Bot)
\ No newline at end of file
+- [Google Meet Bot Examples](https://github.com/Ritika-Das/Google-Meet-Bot)
diff --git a/examples/meeting_bot/recall_ai_poc.py b/examples/meeting_bot/recall_ai_poc.py
index 901fdebba..818ca78b6 100644
--- a/examples/meeting_bot/recall_ai_poc.py
+++ b/examples/meeting_bot/recall_ai_poc.py
@@ -1,5 +1,4 @@
-"""
-Codegen Meeting Bot - Recall.ai Proof of Concept
+"""Codegen Meeting Bot - Recall.ai Proof of Concept
This script demonstrates how to use Recall.ai to create a meeting bot that can:
1. Join a Google Meet or Zoom meeting
@@ -15,127 +14,114 @@
Note: This is a proof-of-concept and not production-ready code.
"""
-import os
+import asyncio
import json
+import os
import time
-import asyncio
+from typing import Any, Optional
+
import requests
-from typing import Dict, Any, Optional, List
# Configuration
RECALL_API_KEY = os.environ.get("RECALL_API_KEY", "your_api_key_here")
RECALL_API_BASE_URL = "https://api.recall.ai/api/v1"
+
class CodegenMeetingBot:
"""A meeting bot that uses Recall.ai to join meetings and process transcripts with Codegen."""
-
+
def __init__(self, api_key: str):
"""Initialize the meeting bot with the Recall.ai API key."""
self.api_key = api_key
- self.headers = {
- "Authorization": f"Token {self.api_key}",
- "Content-Type": "application/json"
- }
-
- def create_bot(self,
- platform: str,
- meeting_url: str,
- bot_name: str = "Codegen Assistant",
- join_at: Optional[str] = None) -> Dict[str, Any]:
- """
- Create a bot to join a meeting.
-
+ self.headers = {"Authorization": f"Token {self.api_key}", "Content-Type": "application/json"}
+
+ def create_bot(self, platform: str, meeting_url: str, bot_name: str = "Codegen Assistant", join_at: Optional[str] = None) -> dict[str, Any]:
+ """Create a bot to join a meeting.
+
Args:
platform: The meeting platform ("zoom", "google_meet", "ms_teams", etc.)
meeting_url: The URL of the meeting to join
bot_name: The display name for the bot
join_at: ISO 8601 timestamp for when the bot should join (None for immediate)
-
+
Returns:
The bot data from the Recall.ai API
"""
endpoint = f"{RECALL_API_BASE_URL}/bot/"
-
- payload = {
- "meeting_url": meeting_url,
- "platform": platform,
- "bot_name": bot_name
- }
-
+
+ payload = {"meeting_url": meeting_url, "platform": platform, "bot_name": bot_name}
+
if join_at:
payload["join_at"] = join_at
-
+
response = requests.post(endpoint, headers=self.headers, json=payload)
response.raise_for_status()
-
+
return response.json()
-
- def get_bot(self, bot_id: str) -> Dict[str, Any]:
- """
- Get information about a bot.
-
+
+ def get_bot(self, bot_id: str) -> dict[str, Any]:
+ """Get information about a bot.
+
Args:
bot_id: The ID of the bot
-
+
Returns:
The bot data from the Recall.ai API
"""
endpoint = f"{RECALL_API_BASE_URL}/bot/{bot_id}/"
-
+
response = requests.get(endpoint, headers=self.headers)
response.raise_for_status()
-
+
return response.json()
-
- def list_bots(self, limit: int = 10) -> List[Dict[str, Any]]:
- """
- List all bots.
-
+
+ def list_bots(self, limit: int = 10) -> list[dict[str, Any]]:
+ """List all bots.
+
Args:
limit: Maximum number of bots to return
-
+
Returns:
List of bot data from the Recall.ai API
"""
endpoint = f"{RECALL_API_BASE_URL}/bot/?limit={limit}"
-
+
response = requests.get(endpoint, headers=self.headers)
response.raise_for_status()
-
+
return response.json().get("results", [])
-
+
async def stream_transcription(self, bot_id: str):
- """
- Stream real-time transcription from a bot.
-
+ """Stream real-time transcription from a bot.
+
Args:
bot_id: The ID of the bot
"""
import websockets
-
+
# Get the bot data to check if it's active
bot = self.get_bot(bot_id)
-
+
if bot.get("status") != "joined":
print(f"Bot is not active in the meeting. Current status: {bot.get('status')}")
return
-
+
# Connect to the transcription websocket
ws_url = f"wss://api.recall.ai/ws/bot/{bot_id}/transcription/"
-
+
async with websockets.connect(ws_url, extra_headers={"Authorization": f"Token {self.api_key}"}) as websocket:
print("Connected to transcription stream. Waiting for transcription...")
-
+
while True:
try:
message = await websocket.recv()
data = json.loads(message)
-
+
if data.get("event") == "transcript_part":
speaker = data.get("speaker", "Unknown")
text = data.get("text", "")
print(f"{speaker}: {text}")
-
+
# Here you would process the transcript with Codegen
# For example, detect if someone is asking a question about Codegen
if "codegen" in text.lower() and "?" in text:
@@ -144,51 +130,50 @@ async def stream_transcription(self, bot_id: str):
# 1. Process the question with Codegen
# 2. Generate a response
# 3. Send the response back to the meeting (via chat or audio)
-
+
except Exception as e:
print(f"Error in transcription stream: {e}")
break
-
- def process_meeting_recording(self, bot_id: str) -> Dict[str, Any]:
- """
- Process a completed meeting recording.
-
+
+ def process_meeting_recording(self, bot_id: str) -> dict[str, Any]:
+ """Process a completed meeting recording.
+
Args:
bot_id: The ID of the bot
-
+
Returns:
Processed meeting data
"""
# Get the bot data
bot = self.get_bot(bot_id)
-
+
if bot.get("status") not in ["left", "ended"]:
print(f"Meeting is not completed yet. Current status: {bot.get('status')}")
return {}
-
+
# Get the recording URL
recording_url = bot.get("video_url")
-
+
if not recording_url:
print("No recording available for this meeting.")
return {}
-
+
print(f"Recording available at: {recording_url}")
-
+
# In a real implementation, you would:
# 1. Download the recording
# 2. Process the full transcript
# 3. Generate a meeting summary with Codegen
# 4. Extract action items
# 5. Store the results
-
+
return {
"meeting_id": bot.get("id"),
"duration": bot.get("duration"),
"recording_url": recording_url,
"platform": bot.get("platform"),
"summary": "This is where the meeting summary would go.",
- "action_items": ["Action item 1", "Action item 2"]
+ "action_items": ["Action item 1", "Action item 2"],
}
@@ -196,23 +181,19 @@ async def main():
"""Main function to demonstrate the Codegen Meeting Bot."""
# Initialize the bot
bot = CodegenMeetingBot(RECALL_API_KEY)
-
+
# Example: Create a bot to join a Google Meet meeting
meeting_url = "https://meet.google.com/abc-defg-hij"
-
+
try:
# Create a bot to join the meeting
print(f"Creating bot to join meeting: {meeting_url}")
- bot_data = bot.create_bot(
- platform="google_meet",
- meeting_url=meeting_url,
- bot_name="Codegen Assistant"
- )
-
+ bot_data = bot.create_bot(platform="google_meet", meeting_url=meeting_url, bot_name="Codegen Assistant")
+
bot_id = bot_data.get("id")
print(f"Bot created with ID: {bot_id}")
print(f"Bot status: {bot_data.get('status')}")
-
+
# Wait for the bot to join the meeting
print("Waiting for bot to join the meeting...")
for _ in range(30): # Wait up to 30 seconds
@@ -221,25 +202,25 @@ async def main():
print("Bot has joined the meeting!")
break
time.sleep(1)
-
+
# Stream transcription in real-time
print("Starting transcription stream...")
await bot.stream_transcription(bot_id)
-
+
# In a real implementation, you would wait for the meeting to end
# For this example, we'll just wait a few seconds
print("Simulating meeting duration (10 seconds)...")
time.sleep(10)
-
+
# Process the meeting recording
print("Processing meeting recording...")
meeting_data = bot.process_meeting_recording(bot_id)
print(f"Meeting data: {json.dumps(meeting_data, indent=2)}")
-
+
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
# Run the main function
- asyncio.run(main())
\ No newline at end of file
+ asyncio.run(main())
diff --git a/examples/meeting_bot/zoom_sdk_poc.js b/examples/meeting_bot/zoom_sdk_poc.js
index b1473c77d..0c213d6ca 100644
--- a/examples/meeting_bot/zoom_sdk_poc.js
+++ b/examples/meeting_bot/zoom_sdk_poc.js
@@ -1,74 +1,84 @@
/**
* Codegen Meeting Bot - Zoom SDK Proof of Concept
- *
+ *
* This script demonstrates how to use the Zoom Meeting SDK to create a meeting bot that can:
* 1. Join a Zoom meeting
* 2. Listen to meeting events
* 3. Interact with the meeting
- *
+ *
* Requirements:
* - Node.js
* - Zoom Meeting SDK credentials
* - Puppeteer for headless browser automation
- *
+ *
* Note: This is a proof-of-concept and not production-ready code.
*/
-const puppeteer = require('puppeteer');
-const express = require('express');
-const bodyParser = require('body-parser');
-const crypto = require('crypto');
-const cors = require('cors');
-const path = require('path');
-const fs = require('fs');
+const puppeteer = require("puppeteer");
+const express = require("express");
+const bodyParser = require("body-parser");
+const crypto = require("crypto");
+const cors = require("cors");
+const path = require("path");
+const fs = require("fs");
// Configuration
const PORT = process.env.PORT || 3000;
-const ZOOM_SDK_KEY = process.env.ZOOM_SDK_KEY || 'your_sdk_key_here';
-const ZOOM_SDK_SECRET = process.env.ZOOM_SDK_SECRET || 'your_sdk_secret_here';
+const ZOOM_SDK_KEY = process.env.ZOOM_SDK_KEY || "your_sdk_key_here";
+const ZOOM_SDK_SECRET = process.env.ZOOM_SDK_SECRET || "your_sdk_secret_here";
// Express app setup
const app = express();
app.use(cors());
app.use(bodyParser.json());
-app.use(express.static('public'));
+app.use(express.static("public"));
// Generate a Zoom Meeting SDK JWT token
function generateZoomToken(sdkKey, sdkSecret, meetingNumber, role) {
- const iat = Math.round(new Date().getTime() / 1000) - 30;
- const exp = iat + 60 * 60 * 2; // Token expires in 2 hours
- const oHeader = { alg: 'HS256', typ: 'JWT' };
-
- const oPayload = {
- sdkKey: sdkKey,
- mn: meetingNumber,
- role: role,
- iat: iat,
- exp: exp,
- tokenExp: exp
- };
-
- const sHeader = JSON.stringify(oHeader);
- const sPayload = JSON.stringify(oPayload);
- const signature = crypto.createHmac('sha256', sdkSecret)
- .update(Buffer.from(sHeader + "." + sPayload).toString('base64'))
- .digest('base64');
-
- return Buffer.from(sHeader).toString('base64') + "." +
- Buffer.from(sPayload).toString('base64') + "." +
- signature;
+ const iat = Math.round(new Date().getTime() / 1000) - 30;
+ const exp = iat + 60 * 60 * 2; // Token expires in 2 hours
+ const oHeader = { alg: "HS256", typ: "JWT" };
+
+ const oPayload = {
+ sdkKey: sdkKey,
+ mn: meetingNumber,
+ role: role,
+ iat: iat,
+ exp: exp,
+ tokenExp: exp,
+ };
+
+ const sHeader = JSON.stringify(oHeader);
+ const sPayload = JSON.stringify(oPayload);
+ const signature = crypto
+ .createHmac("sha256", sdkSecret)
+ .update(Buffer.from(sHeader + "." + sPayload).toString("base64"))
+ .digest("base64");
+
+ return (
+ Buffer.from(sHeader).toString("base64") +
+ "." +
+ Buffer.from(sPayload).toString("base64") +
+ "." +
+ signature
+ );
}
// API endpoint to generate a token
-app.post('/api/token', (req, res) => {
- const { meetingNumber, role } = req.body;
-
- if (!meetingNumber) {
- return res.status(400).json({ error: 'Meeting number is required' });
- }
-
- const token = generateZoomToken(ZOOM_SDK_KEY, ZOOM_SDK_SECRET, meetingNumber, role || 0);
- res.json({ token });
+app.post("/api/token", (req, res) => {
+ const { meetingNumber, role } = req.body;
+
+ if (!meetingNumber) {
+ return res.status(400).json({ error: "Meeting number is required" });
+ }
+
+ const token = generateZoomToken(
+ ZOOM_SDK_KEY,
+ ZOOM_SDK_SECRET,
+ meetingNumber,
+ role || 0,
+ );
+ res.json({ token });
});
// HTML template for the Zoom client
@@ -108,7 +118,7 @@ const zoomClientHtml = `
@@ -184,244 +194,254 @@ const zoomClientHtml = `
`;
// Serve the Zoom client HTML
-app.get('/zoom-client', (req, res) => {
- res.send(zoomClientHtml);
+app.get("/zoom-client", (req, res) => {
+ res.send(zoomClientHtml);
});
// Start the server
app.listen(PORT, () => {
- console.log(`Server running on port ${PORT}`);
+ console.log(`Server running on port ${PORT}`);
});
/**
* CodegenZoomBot class for controlling a Zoom meeting bot
*/
class CodegenZoomBot {
- constructor() {
- this.browser = null;
- this.page = null;
- this.serverUrl = `http://localhost:${PORT}`;
- this.isConnected = false;
- this.meetingData = {
- meetingNumber: '',
- password: '',
- userName: 'Codegen Assistant',
- };
- }
-
- /**
- * Initialize the bot
- */
- async initialize() {
- // Launch a headless browser
- this.browser = await puppeteer.launch({
- headless: true,
- args: [
- '--no-sandbox',
- '--disable-setuid-sandbox',
- '--disable-web-security',
- '--allow-running-insecure-content',
- '--use-fake-ui-for-media-stream',
- '--use-fake-device-for-media-stream',
- ],
- });
-
- // Create a new page
- this.page = await this.browser.newPage();
-
- // Set up event listeners for messages from the Zoom client
- await this.page.exposeFunction('onClientMessage', (message) => {
- const { type, data } = message;
-
- switch (type) {
- case 'CLIENT_READY':
- console.log('Zoom client is ready');
- break;
- case 'JOIN_SUCCESS':
- console.log('Successfully joined the meeting');
- this.isConnected = true;
- break;
- case 'JOIN_ERROR':
- console.error('Failed to join the meeting:', data);
- break;
- case 'CONNECTION_CHANGE':
- console.log('Connection changed:', data);
- break;
- case 'AUDIO_CHANGE':
- console.log('Audio changed:', data);
- break;
- case 'CHAT_RECEIVED':
- console.log('Chat received:', data);
- this.processChat(data);
- break;
- default:
- console.log('Unknown message type:', type);
- }
- });
-
- // Set up message listener
- await this.page.evaluateOnNewDocument(() => {
- window.addEventListener('message', (event) => {
- window.onClientMessage(event.data);
- });
- });
-
- // Navigate to the Zoom client page
- await this.page.goto(`${this.serverUrl}/zoom-client`);
-
- console.log('Bot initialized');
- }
-
- /**
- * Join a Zoom meeting
- * @param {string} meetingNumber - The Zoom meeting number
- * @param {string} password - The Zoom meeting password
- */
- async joinMeeting(meetingNumber, password) {
- this.meetingData.meetingNumber = meetingNumber;
- this.meetingData.password = password;
-
- // Get a token for the meeting
- const response = await fetch(`${this.serverUrl}/api/token`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- meetingNumber,
- role: 0, // 0 for attendee, 1 for host
- }),
- });
-
- const { token } = await response.json();
-
- // Send a message to the Zoom client to join the meeting
- await this.page.evaluate((data) => {
- window.postMessage({
- type: 'JOIN_MEETING',
- data: {
- meetingNumber: data.meetingNumber,
- token: data.token,
- userName: data.userName,
- password: data.password,
- },
- }, '*');
- }, {
- meetingNumber,
- token,
- userName: this.meetingData.userName,
- password,
- });
-
- console.log(`Joining meeting: ${meetingNumber}`);
- }
-
- /**
- * Leave the current Zoom meeting
- */
- async leaveMeeting() {
- if (!this.isConnected) {
- console.log('Not connected to a meeting');
- return;
- }
-
- // Send a message to the Zoom client to leave the meeting
- await this.page.evaluate(() => {
- window.postMessage({
- type: 'LEAVE_MEETING',
- }, '*');
- });
-
- this.isConnected = false;
- console.log('Left the meeting');
- }
-
- /**
- * Process a chat message from the meeting
- * @param {Object} chatData - The chat message data
- */
- async processChat(chatData) {
- const { message, sender } = chatData;
-
- // Check if the message is directed to Codegen
- if (message.toLowerCase().includes('codegen') && message.includes('?')) {
- console.log(`Processing question from ${sender}: ${message}`);
-
- // In a real implementation, you would:
- // 1. Process the question with Codegen
- // 2. Generate a response
- // 3. Send the response back to the chat
-
- // For this example, we'll just send a hardcoded response
- await this.sendChatMessage(`Hello ${sender}, I'm the Codegen Assistant. I'm here to help with your Codegen questions!`);
- }
- }
-
- /**
- * Send a chat message to the meeting
- * @param {string} message - The message to send
- */
- async sendChatMessage(message) {
- if (!this.isConnected) {
- console.log('Not connected to a meeting');
- return;
- }
-
- // In a real implementation, you would use the Zoom SDK to send a chat message
- // For this example, we'll just log the message
- console.log(`Sending chat message: ${message}`);
- }
-
- /**
- * Close the bot
- */
- async close() {
- if (this.isConnected) {
- await this.leaveMeeting();
- }
-
- if (this.browser) {
- await this.browser.close();
- }
-
- console.log('Bot closed');
- }
+ constructor() {
+ this.browser = null;
+ this.page = null;
+ this.serverUrl = `http://localhost:${PORT}`;
+ this.isConnected = false;
+ this.meetingData = {
+ meetingNumber: "",
+ password: "",
+ userName: "Codegen Assistant",
+ };
+ }
+
+ /**
+ * Initialize the bot
+ */
+ async initialize() {
+ // Launch a headless browser
+ this.browser = await puppeteer.launch({
+ headless: true,
+ args: [
+ "--no-sandbox",
+ "--disable-setuid-sandbox",
+ "--disable-web-security",
+ "--allow-running-insecure-content",
+ "--use-fake-ui-for-media-stream",
+ "--use-fake-device-for-media-stream",
+ ],
+ });
+
+ // Create a new page
+ this.page = await this.browser.newPage();
+
+ // Set up event listeners for messages from the Zoom client
+ await this.page.exposeFunction("onClientMessage", (message) => {
+ const { type, data } = message;
+
+ switch (type) {
+ case "CLIENT_READY":
+ console.log("Zoom client is ready");
+ break;
+ case "JOIN_SUCCESS":
+ console.log("Successfully joined the meeting");
+ this.isConnected = true;
+ break;
+ case "JOIN_ERROR":
+ console.error("Failed to join the meeting:", data);
+ break;
+ case "CONNECTION_CHANGE":
+ console.log("Connection changed:", data);
+ break;
+ case "AUDIO_CHANGE":
+ console.log("Audio changed:", data);
+ break;
+ case "CHAT_RECEIVED":
+ console.log("Chat received:", data);
+ this.processChat(data);
+ break;
+ default:
+ console.log("Unknown message type:", type);
+ }
+ });
+
+ // Set up message listener
+ await this.page.evaluateOnNewDocument(() => {
+ window.addEventListener("message", (event) => {
+ window.onClientMessage(event.data);
+ });
+ });
+
+ // Navigate to the Zoom client page
+ await this.page.goto(`${this.serverUrl}/zoom-client`);
+
+ console.log("Bot initialized");
+ }
+
+ /**
+ * Join a Zoom meeting
+ * @param {string} meetingNumber - The Zoom meeting number
+ * @param {string} password - The Zoom meeting password
+ */
+ async joinMeeting(meetingNumber, password) {
+ this.meetingData.meetingNumber = meetingNumber;
+ this.meetingData.password = password;
+
+ // Get a token for the meeting
+ const response = await fetch(`${this.serverUrl}/api/token`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ meetingNumber,
+ role: 0, // 0 for attendee, 1 for host
+ }),
+ });
+
+ const { token } = await response.json();
+
+ // Send a message to the Zoom client to join the meeting
+ await this.page.evaluate(
+ (data) => {
+ window.postMessage(
+ {
+ type: "JOIN_MEETING",
+ data: {
+ meetingNumber: data.meetingNumber,
+ token: data.token,
+ userName: data.userName,
+ password: data.password,
+ },
+ },
+ "*",
+ );
+ },
+ {
+ meetingNumber,
+ token,
+ userName: this.meetingData.userName,
+ password,
+ },
+ );
+
+ console.log(`Joining meeting: ${meetingNumber}`);
+ }
+
+ /**
+ * Leave the current Zoom meeting
+ */
+ async leaveMeeting() {
+ if (!this.isConnected) {
+ console.log("Not connected to a meeting");
+ return;
+ }
+
+ // Send a message to the Zoom client to leave the meeting
+ await this.page.evaluate(() => {
+ window.postMessage(
+ {
+ type: "LEAVE_MEETING",
+ },
+ "*",
+ );
+ });
+
+ this.isConnected = false;
+ console.log("Left the meeting");
+ }
+
+ /**
+ * Process a chat message from the meeting
+ * @param {Object} chatData - The chat message data
+ */
+ async processChat(chatData) {
+ const { message, sender } = chatData;
+
+ // Check if the message is directed to Codegen
+ if (message.toLowerCase().includes("codegen") && message.includes("?")) {
+ console.log(`Processing question from ${sender}: ${message}`);
+
+ // In a real implementation, you would:
+ // 1. Process the question with Codegen
+ // 2. Generate a response
+ // 3. Send the response back to the chat
+
+ // For this example, we'll just send a hardcoded response
+ await this.sendChatMessage(
+ `Hello ${sender}, I'm the Codegen Assistant. I'm here to help with your Codegen questions!`,
+ );
+ }
+ }
+
+ /**
+ * Send a chat message to the meeting
+ * @param {string} message - The message to send
+ */
+ async sendChatMessage(message) {
+ if (!this.isConnected) {
+ console.log("Not connected to a meeting");
+ return;
+ }
+
+ // In a real implementation, you would use the Zoom SDK to send a chat message
+ // For this example, we'll just log the message
+ console.log(`Sending chat message: ${message}`);
+ }
+
+ /**
+ * Close the bot
+ */
+ async close() {
+ if (this.isConnected) {
+ await this.leaveMeeting();
+ }
+
+ if (this.browser) {
+ await this.browser.close();
+ }
+
+ console.log("Bot closed");
+ }
}
/**
* Example usage
*/
async function main() {
- const bot = new CodegenZoomBot();
-
- try {
- // Initialize the bot
- await bot.initialize();
-
- // Join a meeting
- const meetingNumber = '123456789';
- const password = 'password';
- await bot.joinMeeting(meetingNumber, password);
-
- // Keep the bot running for a while
- console.log('Bot is running. Press Ctrl+C to exit.');
-
- // Handle process termination
- process.on('SIGINT', async () => {
- console.log('Shutting down...');
- await bot.close();
- process.exit(0);
- });
-
- } catch (error) {
- console.error('Error:', error);
- await bot.close();
- }
+ const bot = new CodegenZoomBot();
+
+ try {
+ // Initialize the bot
+ await bot.initialize();
+
+ // Join a meeting
+ const meetingNumber = "123456789";
+ const password = "password";
+ await bot.joinMeeting(meetingNumber, password);
+
+ // Keep the bot running for a while
+ console.log("Bot is running. Press Ctrl+C to exit.");
+
+ // Handle process termination
+ process.on("SIGINT", async () => {
+ console.log("Shutting down...");
+ await bot.close();
+ process.exit(0);
+ });
+ } catch (error) {
+ console.error("Error:", error);
+ await bot.close();
+ }
}
// Run the example if this script is executed directly
if (require.main === module) {
- main();
+ main();
}
-module.exports = CodegenZoomBot;
\ No newline at end of file
+module.exports = CodegenZoomBot;