From c08b4193bd8847f7e0bbc0bbd01400403cb7a1ba Mon Sep 17 00:00:00 2001 From: aalpat4 <149398159+aalpat4@users.noreply.github.com> Date: Tue, 26 Mar 2024 17:31:52 -0400 Subject: [PATCH] Add files via upload --- ...ize_Google_Meet_meetings_with_Cohere.ipynb | 827 ++++++++++++++++++ 1 file changed, 827 insertions(+) create mode 100644 notebooks/guides/Summarize_Google_Meet_meetings_with_Cohere.ipynb diff --git a/notebooks/guides/Summarize_Google_Meet_meetings_with_Cohere.ipynb b/notebooks/guides/Summarize_Google_Meet_meetings_with_Cohere.ipynb new file mode 100644 index 00000000..490219b8 --- /dev/null +++ b/notebooks/guides/Summarize_Google_Meet_meetings_with_Cohere.ipynb @@ -0,0 +1,827 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "![Cohere-Logo-Color-RGB.png](data:image/png;base64,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)" + ], + "metadata": { + "id": "AU2dMXfqjkZI" + } + }, + { + "cell_type": "markdown", + "source": [ + "Capturing meeting notes is often a time consuming process, requiring a member to dedicate their attention to capturing notes and away from participating.\n", + "\n", + "The following cookbook walks you through building your own meeting auto-notes tool for Google Meet + Google Calendar events, using the Cohere API, Google Calendar and Drive APIs and transcripts generated from Google Meet's \"Transcribe\" feature.\n", + "\n", + "This cookbook will walk you through:\n", + "\n", + "\n", + "* Downloading meeting transcript text from your Google Calendar Events that have a Google Meet link with transcripts enabled\n", + "* Generating an auto-notes summary of the meeting transcript\n", + "* Uploading the auto-notes to the Google Calendar Event and notifying participants" + ], + "metadata": { + "id": "2QNJMn5xX3bi" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Table of contents\n", + "\n", + "1. [Create your project](###step-1-create-your-project)\n", + "2. [Set up your dependencies](###step-2-set-up-your-dependencies)\n", + "3. [Access your Google Calendar Events and download transcripts](###step-3-access-your-google-calendar-events-and-download-transcripts)\n", + "4. [Generate an auto-notes summary](###step-4-generate-an-auto-notes-summary)\n", + "5. [Upload summary to event and (optionally) share with participants](###step-5-upload-summary-to-event-and-optionally-share-with-participants)\n", + "\n" + ], + "metadata": { + "id": "A0GgMxSeu6QX" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Step 1: Create your project" + ], + "metadata": { + "id": "EaJ9f-OJX9p3" + } + }, + { + "cell_type": "markdown", + "source": [ + "We're going to be using Google Calendar APIs to access your calendar events and download meeting transcript attachments. To do this, we first have to set up authentication for our app to access Google Calendar.\n", + "\n", + "\n", + "\n", + "1. Create a project in your [Google Cloud Console](https://console.cloud.google.com) or open an existing project.\n", + "2. Search \"Google Calendar API\" in your search bar, and click \"Enable\" on the API page\n", + "3. Search \"Google Drive API\" and click \"Enable\" on the API page.\n", + "4. Under \"Credentials\" click \"Create Credentials\" -> \"Oath Client ID\"\n", + "5. Follow the Application creation flow, and select \"Desktop app\" as the Application Type. (We will cover how to modify this for remote deployment and chron job execution later).\n", + " - Note: Make sure under scopes, select \"Google Calendar API\" and \"Google Drive API\"\n", + "6. Copy the CLIENT_ID and CLIENT_SECRET. You will need them in the next steps\n" + ], + "metadata": { + "id": "fynTgqc6YBhI" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Step 2: Set up your dependencies" + ], + "metadata": { + "id": "Ape8tiqS8eJk" + } + }, + { + "cell_type": "code", + "source": [ + "%%capture\n", + "pip install --upgrade google-api-python-client google-auth-httplib2 google-cloud-storage cohere" + ], + "metadata": { + "id": "cIKddP3lSPLp" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### Step 3: Access your Google Calendar Events and download transcripts" + ], + "metadata": { + "id": "irZoKGmkSWnt" + } + }, + { + "cell_type": "markdown", + "source": [ + "First, let's set up authentication creds so you can access the Google Calendar API" + ], + "metadata": { + "id": "NYS3l2a35Mfw" + } + }, + { + "cell_type": "code", + "source": [ + "import json\n", + "import os\n", + "import googleapiclient.discovery\n", + "import google.oauth2.service_account\n", + "import pickle\n", + "from google_auth_oauthlib.flow import InstalledAppFlow\n", + "from google_auth_oauthlib.flow import Flow\n", + "from google.oauth2.credentials import Credentials\n", + "from google.auth.transport.requests import Request\n", + "from getpass import getpass\n", + "from typing import Any, Dict, List, Optional\n", + "\n", + "# Scopes that offer read/write access to Google Calendar and Google Drive\n", + "SCOPES = ['https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/drive']\n", + "\n", + "#### REPLACE WITH FILEPATH TO YOUR CREDS ####\n", + "client_id = getpass(\"Client ID: \")\n", + "client_secret = getpass(\"Client Secret: \")\n", + "\n", + "def get_credentials(write_to_cache=True, read_from_cache=True):\n", + " creds = None\n", + "\n", + " # Attempt to load saved credentials\n", + " if read_from_cache and os.path.exists('token.pickle'):\n", + " with open('token.pickle', 'rb') as token:\n", + " return pickle.load(token)\n", + " else:\n", + " if not creds or not creds.valid:\n", + " # Refresh if creds are expired\n", + " if creds and creds.expired and creds.refresh_token:\n", + " creds.refresh(Request())\n", + " return creds\n", + " else:\n", + " client_config = {\n", + " \"installed\": {\n", + " \"client_id\": client_id,\n", + " \"client_secret\": client_secret,\n", + " \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n", + " \"token_uri\": \"https://oauth2.googleapis.com/token\",\n", + " \"redirect_uris\": [\"urn:ietf:wg:oauth:2.0:oob\", \"http://localhost\"]\n", + " }\n", + " }\n", + " flow = InstalledAppFlow.from_client_config(client_config, SCOPES)\n", + "\n", + " # Redirect URI set to following to work for Google collab,\n", + " # Can replace with a locally hosted server if running as a desktop script\n", + " flow.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'\n", + " auth_url, _ = flow.authorization_url(prompt='consent')\n", + " print(f\"Please go to this URL and authorize access: {auth_url}\")\n", + " code = input(\"Enter the authorization code: \")\n", + " flow.fetch_token(code=code)\n", + " creds = flow.credentials\n", + " if write_to_cache:\n", + " with open('token.pickle', 'wb') as token:\n", + " pickle.dump(creds, token)\n", + " return creds" + ], + "metadata": { + "id": "CG8lTDGL2LUJ", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "5ce65c32-d02f-4409-e173-61b0e1bda670" + }, + "execution_count": null, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Client ID: ··········\n", + "Client Secret: ··········\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Now, let's use the creds in a method to read all the Google Calendar events from today." + ], + "metadata": { + "id": "auOX26VkGAuz" + } + }, + { + "cell_type": "code", + "source": [ + "from googleapiclient.discovery import build\n", + "creds = get_credentials()\n", + "calender_service = build(\"calendar\", \"v3\", credentials=creds)\n", + "\n", + "def get_calendar_events(start_time, end_time):\n", + " print(f\"Getting events from {start_time} to: {end_time}\")\n", + " events_result = (\n", + " calender_service.events()\n", + " .list(\n", + " calendarId=\"primary\",\n", + " timeMin=start_time,\n", + " timeMax=end_time\n", + " )\n", + " .execute()\n", + " )\n", + " return events_result.get(\"items\", [])\n" + ], + "metadata": { + "id": "VVebie1OGJ9p", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "f5286dac-9c14-4ccf-d209-4172ed692cbb" + }, + "execution_count": null, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Please go to this URL and authorize access: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=634741174732-lom4tq4rugtbpbi0l5qpkdt52gqhhv9c.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&state=YmqLUArgd9TNZVMzJQsytOYYoSG6lJ&prompt=consent&access_type=offline\n", + "Enter the authorization code: 4/1AeaYSHC-7FbawGHYxWUlGyEgUBslBaITPSHo08mH9VzwaXQN9ReoMZc6GCQ\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's test out our code by printing the names of all the meetings for the last 8 hours" + ], + "metadata": { + "id": "8kQ_68m3hV8p" + } + }, + { + "cell_type": "code", + "source": [ + "# Get meetings for last 8 hours\n", + "import datetime\n", + "\n", + "lookback_hours = 8\n", + "start_time = (datetime.datetime.utcnow() - datetime.timedelta(hours=lookback_hours)).isoformat() + \"Z\"\n", + "end_time = datetime.datetime.utcnow().isoformat() + \"Z\"\n", + "events = get_calendar_events(start_time=start_time, end_time=end_time)\n", + "for event in events:\n", + " print(event[\"summary\"])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RZ8F1KS1hZhq", + "outputId": "e5f59dec-197f-4840-fcde-afa86c4895dc" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Getting events from 2024-03-16T06:17:13.874343Z to: 2024-03-16T14:17:13.874400Z\n", + "Flight to Zürich (UA 9747)\n", + "Flight to Zürich (UA 9729)\n", + "Test Meeting\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Now, let's grab the attachments from the meeting, and extract all those which contain a \"- Transcript\" in their title. These reflect meeting transcripts captured using the Google Meet \"Transcribe\" feature.\n", + "\n", + "**Note** If you don't have a meeting for which you've enabled \"Transcribe\" readily handy, you can make a copy of [this transcript from a Parliament meeting](https://docs.google.com/document/d/1vIVGWh2mIM220yc-hd0KP5VEFGa2eU8ILFBfFLsr4nI/edit#heading=h.pvm3n0pul0ky) and attach it to one of your Google Calendar Events you'll be testing with." + ], + "metadata": { + "id": "qBwZPN46Pxzj" + } + }, + { + "cell_type": "code", + "source": [ + "# This substring is how we will filter for the Google Docs created automatically by Google Meet\n", + "# to capture meeting transcripts\n", + "TRANSCRIPT_ATTACHMENT_POSTSCRIPT = \"- Transcript\"\n", + "\n", + "def get_attachments_for_event(event_id: str):\n", + " event = calender_service.events().get(calendarId=\"primary\",\n", + " eventId=event_id).execute()\n", + " if 'attachments' in event:\n", + " return event[\"attachments\"]\n", + " else:\n", + " return None\n", + "\n", + "def get_attendees_for_event(event_id: str):\n", + " event = calender_service.events().get(calendarId=\"primary\", eventId=event_id).execute()\n", + " if 'attendees' in event:\n", + " return event[\"attendees\"]\n", + " else:\n", + " return None\n", + "\n", + "def get_meeting_transcript_attachment(attachments):\n", + " if attachments is None or len(attachments) == 0:\n", + " print(\"No attachments provided to get_meeting_transcript_from_attachments\")\n", + " return None\n", + "\n", + " annotation_attachments = [attachment for attachment in attachments if TRANSCRIPT_ATTACHMENT_POSTSCRIPT in attachment[\"title\"]]\n", + " if annotation_attachments is None or len(annotation_attachments) == 0:\n", + " print(\"No annotation attachments found\")\n", + " return None\n", + " annotation_attachment = annotation_attachments[0]\n", + " return annotation_attachment\n" + ], + "metadata": { + "id": "LSZT3G0XPxLQ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "We can now download the text from the Transcript document, which we will use for the auto-notes summary. For this, we'll need to use the Google Drive API." + ], + "metadata": { + "id": "4aGg9RHkWwXJ" + } + }, + { + "cell_type": "code", + "source": [ + "import re\n", + "import io\n", + "from googleapiclient.http import MediaIoBaseDownload\n", + "\n", + "drive_client = build('drive', 'v3', credentials=creds)\n", + "\n", + "def download_from_attachment(attachment_id, download_path=\"downloads\"):\n", + " attachment_data = drive_client.files().get(fileId=attachment_id, supportsAllDrives=True).execute()\n", + "\n", + " file_mime_type = attachment_data['mimeType']\n", + " if 'application/vnd.google-apps.document' not in file_mime_type:\n", + " raise ValueError(\"Attachment is not a Google doc\")\n", + "\n", + " # Filename to save transcript text\n", + " local_filename = attachment_data['name']\n", + " local_filename = re.sub(r'[^\\w\\s.-]', '', local_filename)\n", + " local_filename = local_filename.replace(' ', '_')\n", + " if not os.path.exists(download_path):\n", + " os.makedirs(download_path)\n", + "\n", + " # Save transcript text file locally\n", + " file_path = os.path.join(download_path, f\"{local_filename}.txt\")\n", + "\n", + " request = drive_client.files().export_media(fileId=attachment_id, mimeType='text/plain')\n", + " fh = io.FileIO(file_path, 'wb')\n", + " downloader = MediaIoBaseDownload(fh, request)\n", + "\n", + " done = False\n", + " while not done:\n", + " status, done = downloader.next_chunk()\n", + " print(f\"Downloaded {status.progress() * 100:.2f}% of {local_filename}.txt\")\n", + "\n", + " # Return text from file\n", + " with open(file_path, 'r') as f:\n", + " text = f.read()\n", + " return {\n", + " \"file_path\": file_path,\n", + " \"content\": text,\n", + " \"title\": attachment_data['name']\n", + " }" + ], + "metadata": { + "id": "3M3OL0eGW614" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's put it all together to get the Google Meet transcripts for all Google Calendar events for the past 12 hours." + ], + "metadata": { + "id": "J0ktUazgX63G" + } + }, + { + "cell_type": "code", + "source": [ + "import datetime\n", + "LOOKBACK_NUM_HOURS = 12\n", + "\n", + "# Get meetings for last LOOKBACK_NUM_HOURS # of hours\n", + "start_time = (datetime.datetime.utcnow() - datetime.timedelta(hours=LOOKBACK_NUM_HOURS)).isoformat() + \"Z\"\n", + "end_time = datetime.datetime.utcnow().isoformat() + \"Z\"\n", + "events = get_calendar_events(start_time=start_time, end_time=end_time)\n", + "\n", + "transcripts_for_events = {}\n", + "for event in events:\n", + " attachments = get_attachments_for_event(event_id=event[\"id\"])\n", + " attendees= get_attendees_for_event(event_id=event[\"id\"])\n", + " event_name = event[\"summary\"]\n", + " meeting_transcript_attachment = get_meeting_transcript_attachment(attachments)\n", + " if meeting_transcript_attachment is None or len(meeting_transcript_attachment) < 1:\n", + " print(f\"No transcripts found for event: {event_name}. Skipping\")\n", + " continue\n", + " transcript = download_from_attachment(meeting_transcript_attachment[\"fileId\"])\n", + " transcripts_for_events[event[\"id\"]] = {\n", + " \"transcript\": transcript,\n", + " \"attendees\": attendees\n", + " }\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "AtQP2cmKYLH7", + "outputId": "0fbc2e18-c9ef-48d2-fb5a-28502994c4cc" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Getting events from 2024-03-16T01:59:07.354257Z to: 2024-03-16T13:59:07.354353Z\n", + "No attachments provided to get_meeting_transcript_from_attachments\n", + "No transcripts found for event: Flight to Zürich (UA 9747). Skipping\n", + "No attachments provided to get_meeting_transcript_from_attachments\n", + "No transcripts found for event: Flight to Zürich (UA 9729). Skipping\n", + "Downloaded 100.00% of Example_meeting_transcript_-_Transcript.txt\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Step 4: Generate an auto-notes summary\n", + "\n", + "---\n", + "\n", + "Now that we have the Google transcript, we'll use Cohere's `co.chat` API to generate the summary. We could just ask for a generic summary of meeting. Instead, we can also request the model to attend to specific elements, e.g.:\n", + "\n", + "1. What are the action items that follow from the meeting?\n", + "2. What were the perspectives or views expressed by each participant?\n", + "\n", + "We'll implement the generic summary below, with the option to toggle modes 1. and 2. For more recipes for tailoring your meeting summaries, you can refer to [this cookbook](https://colab.research.google.com/drive/1XqRpJH7qRnRTbOEt6kthwqZG6gtEn4gN).\n" + ], + "metadata": { + "id": "wfGx7l3pS35v" + } + }, + { + "cell_type": "markdown", + "source": [ + "First, let's set up the Cohere client with a Cohere API key." + ], + "metadata": { + "id": "bglRhN3wDOmq" + } + }, + { + "cell_type": "code", + "source": [ + "import cohere\n", + "\n", + "co_api_key = getpass(\"Cohere API Key: \")\n", + "co = cohere.Client(api_key=co_api_key)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FmzPZTqgDQvE", + "outputId": "1b1ad1e9-d248-469b-935c-4586cefcaeba" + }, + "execution_count": null, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cohere API Key: ··········\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "from enum import Enum\n", + "\n", + "class MeetingOptions(Enum):\n", + " ACTION_ITEMS = \"action_items\"\n", + " PERSPECTIVES = \"meeting_perspectives\"\n", + "\n", + "\n", + "def generate_aut_notes_summary_for_text(meeting: str, options: Optional[List[MeetingOptions]] = []) -> str:\n", + " \"\"\"\n", + " Uses co.chat to summarise the Google Meet transcript\n", + " \"\"\"\n", + "\n", + " preamble = \"\"\"\\\n", + "You're a highly-skilled AI that excels at producing exhaustive, complete summaries of meeting transcripts. \\\n", + "Follow the instructions below to summarize the meeting transcript to the best of your abilities. \\\n", + "Ensure that your responses are accurate and truthful, and that you follow the instructions to the letter, \\\n", + "regardless of their complexity.\n", + " \"\"\"\n", + "\n", + " postamble = \"\"\"\\\n", + "Don't include preambles, postambles or explanations, but respond only with the requested summary or summaries.\n", + " \"\"\"\n", + "\n", + " instructions = build_instructions(options)\n", + " instructions = instructions + \"\\n\" + postamble\n", + " prompt = f\"\"\"\n", + " ## meeting transcript\n", + " {meeting}\n", + "\n", + " ## instructions\n", + " {instructions}\n", + "\n", + " ## answer\n", + " \"\"\"\n", + "\n", + " # Generate summary\n", + " resp = co.chat(\n", + " message=prompt,\n", + " preamble=preamble,\n", + " model=\"command-r\",\n", + " prompt_truncation=\"AUTO\",\n", + " temperature=0.3\n", + " )\n", + " return resp.text\n", + "\n", + "def build_instructions(options: Optional[List[MeetingOptions]] = []) -> str:\n", + " \"\"\"\n", + " Helper function that composes the instructions based on options provided by the user\n", + " \"\"\"\n", + "\n", + " instructions = \"Produce a summary of the meeting transcript, including all key events, discussion items and decisions.\"\n", + " formatting = \"Format your answer in the form of bullets.\"\n", + "\n", + " valid_options = set([MeetingOptions.ACTION_ITEMS, MeetingOptions.PERSPECTIVES])\n", + " requested_options = set(options).intersection(valid_options)\n", + " if requested_options != options:\n", + " print(f\"Only executing known options: {requested_options}\")\n", + "\n", + " if not requested_options:\n", + " instructions = instructions + \"\\n\" + formatting\n", + " else:\n", + " # Compose instructions, based on the options\n", + " counter = 0\n", + "\n", + " if MeetingOptions.ACTION_ITEMS in requested_options:\n", + " instructions_action_items = \"\"\"\\\n", + "In addition, produce a second summary of the meeting transcript focused exclusively around action items. \\\n", + "Make sure to include the person each action item is assigned to.\"\"\"\n", + " instructions = instructions + \"\\n\" + instructions_action_items\n", + " counter += 1\n", + "\n", + " if MeetingOptions.PERSPECTIVES in requested_options:\n", + " position = \"second\" if counter == 0 else \"third\"\n", + " instructions_perspectives = f\"\"\"\\\n", + "In addition, produce a {position} summary of the meeting transcript summarizing the perspective of every speaker.\"\"\"\n", + " instructions = instructions + \"\\n\" + instructions_perspectives\n", + "\n", + " # Add formatting at the end\n", + " instructions = instructions + \"\\n\" + formatting\n", + "\n", + " return instructions" + ], + "metadata": { + "id": "LvZY35wnS88K" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's try it out! We'll use the method above to generate an auto-notes summary for each event we pulled earlier. For this demo, we'll use both the ACTION_ITEMS and PERSPECTIVES options to get both action items and perspective summaries from the meeting transcripts." + ], + "metadata": { + "id": "EwFdmd4zldWS" + } + }, + { + "cell_type": "code", + "source": [ + "auto_notes_for_events = {}\n", + "for event_id in transcripts_for_events.keys():\n", + " transcript = transcripts_for_events[event_id][\"transcript\"]\n", + " transcript_text = transcript[\"content\"]\n", + " auto_notes_text = generate_aut_notes_summary_for_text(meeting=transcript_text, options=[MeetingOptions.ACTION_ITEMS, MeetingOptions.PERSPECTIVES])\n", + " print(\"Successfully generated auto-notes for transcript for event id: \", event_id)\n", + " auto_notes_for_events[event_id] = auto_notes_text" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DdTGuMLilyim", + "outputId": "aede3c71-f89e-4678-f2be-d98434bb488c" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Only executing known options: {, }\n", + "Successfully generated auto-notes for transcript for event id: 78mto429um7njc1io1msjcamdn\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Step 5: Upload summary to event and (optionally) share with participants" + ], + "metadata": { + "id": "DDsdurSYTBk_" + } + }, + { + "cell_type": "markdown", + "source": [ + "Finally, we will create a Google Doc from the generated auto-notes, attach the notes to the original Google Calendar event, and notify all participants (optional).\n", + "\n", + "The following methods will help create the Google Doc from text and share them with the meeting participants." + ], + "metadata": { + "id": "C5Fn_Embj91o" + } + }, + { + "cell_type": "code", + "source": [ + "from googleapiclient.http import MediaFileUpload\n", + "\n", + "def share_google_doc(doc_id: str,\n", + " share_with: Dict[str, Any],\n", + " permission: str,\n", + " send_notification_emails: bool):\n", + " permission = {\n", + " 'role': permission,\n", + " 'type': 'user',\n", + " 'emailAddress': share_with[\"email\"],\n", + " }\n", + " drive_client.permissions().create(fileId=doc_id, body=permission, sendNotificationEmail=send_notification_emails).execute()\n", + "\n", + "def write_to_file(filename, content):\n", + " with open(filename, 'w') as file:\n", + " file.write(content)\n", + " print(f\"Content written to {filename}\")\n", + "\n", + "def generate_google_doc_from_notes_summary_text(text, title: str, share_with: List[Dict[str, Any]], send_notification_emails: bool):\n", + " tmp_filename = \"tmp_autonotes.txt\"\n", + " write_to_file(tmp_filename, text)\n", + " media = MediaFileUpload(tmp_filename, mimetype='text/plain')\n", + " file_metadata = {\n", + " 'name': title,\n", + " 'mimeType': 'application/vnd.google-apps.document',\n", + " }\n", + " doc = drive_client.files().create(body=file_metadata,\n", + " media_body=media,\n", + " supportsAllDrives=True).execute()\n", + " for user in share_with:\n", + " try:\n", + " share_google_doc(doc['id'], user, 'writer', send_notification_emails=send_notification_emails)\n", + " except Exception as e:\n", + " print(f\"Failed to share google doc with user: {user} with error: {e}\")\n", + " return doc\n" + ], + "metadata": { + "id": "o5OYLIzyTI9n" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now that we've got our auto notes text, let's create a Google Doc with the text, share it with the meeting participants. We'll title this doc with the meeting name + \" - Auto Notes\". We'll also use the send_notification_emails parameter to notify the event attendees." + ], + "metadata": { + "id": "YUhBVHSpkHbd" + } + }, + { + "cell_type": "code", + "source": [ + "notes_gdocs_for_events = {}\n", + "\n", + "# Generate auto-notes google doc for all events\n", + "for event in events:\n", + " if event[\"id\"] not in auto_notes_for_events.keys():\n", + " print(\"Event does not have auto notes. Skipping\")\n", + " continue\n", + " auto_notes_text = auto_notes_for_events[event[\"id\"]]\n", + " doc_title = event[\"summary\"] + \" - Auto Notes\"\n", + " if \"attendees\" not in event:\n", + " print(\"Skipping, no attendees for event: \", event[\"summary\"])\n", + " continue\n", + " attendees = event[\"attendees\"]\n", + " auto_notes_google_doc = generate_google_doc_from_notes_summary_text(text=auto_notes_text,\n", + " title=doc_title,\n", + " share_with=attendees,\n", + " send_notification_emails=True)\n", + " notes_gdocs_for_events[event[\"id\"]] = auto_notes_google_doc" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2CClpuMGECqw", + "outputId": "8d044618-40f9-42df-ff2e-231b8f5f9573" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Event does not have auto notes. Skipping\n", + "Event does not have auto notes. Skipping\n", + "Content written to tmp_autonotes.txt\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Great! Now, you should see a Google Doc with the auto-notes in your Google Drive. Now let's finish things up by uploading the Google Doc as an attachment to the original Google Calendar event" + ], + "metadata": { + "id": "bo5Xh0RdHbVa" + } + }, + { + "cell_type": "code", + "source": [ + "def get_doc_info(id: str):\n", + " return drive_client.files().get(fileId=id,\n", + " fields='webViewLink, name, mimeType').execute()\n", + "\n", + "def upload_doc_to_event(doc: Dict[str, Any], event_id: str):\n", + " event = calender_service.events().get(calendarId=\"primary\",\n", + " eventId=event_id).execute()\n", + " attachment = {\n", + " 'fileUrl': doc[\"webViewLink\"],\n", + " 'mimeType': doc['mimeType'],\n", + " 'title': doc['name']\n", + " }\n", + "\n", + " if 'attachments' not in event:\n", + " event['attachments'] = []\n", + " event['attachments'].append(attachment)\n", + " changes = {\n", + " 'attachments': event['attachments']\n", + " }\n", + " calender_service.events().patch(calendarId=\"primary\",\n", + " eventId=event_id,\n", + " body=changes,\n", + " supportsAttachments=True).execute()\n", + "\n", + "# Upload notes for all events\n", + "for event_id, gdoc in notes_gdocs_for_events.items():\n", + " gdoc_info = get_doc_info(id=gdoc[\"id\"])\n", + " upload_doc_to_event(gdoc_info, event_id)" + ], + "metadata": { + "id": "JDEnwCiJHlPG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Conclusion\n", + "\n", + "In this cookbook, we've shown how you can use Cohere API's, Google Calendar and Drive APIs and the \"Transcribe\" feature of Google Meet to automatically generate summaries and notes for your meetings. We've also shown you how you can customize what you want to see in your notes with options such as action items and perspectives.\n", + "\n", + "To scale your work and automatically run this for all your meetings and the meetings of others in your organization, you can deploy this work as a [Google Cloud Function](https://cloud.google.com/functions?hl=en) using [a Google service account](https://cloud.google.com/iam/docs/service-account-overview) with [domain-wide delegation](https://support.google.com/a/answer/162106?hl=en). You can also schedule this to run automatically for all your meetings at scheduled intervals using [Google Cloud Scheduler](https://cloud.google.com/scheduler) to trigger your Cloud Function.\n", + "\n", + "Follow the linked documentation to learn how, or contact us to help you get the most out of your meeting summaries!" + ], + "metadata": { + "id": "r6RGYVr8oKHq" + } + } + ] +} \ No newline at end of file