import gradio as gr from transformers import pipeline import torch import moviepy.editor as mp import os from googleapiclient.discovery import build from google.oauth2 import credentials from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request from googleapiclient.http import MediaIoBaseDownload from googleapiclient.errors import HttpError import uuid # Device setup device = "cpu" # Using CPU to avoid CUDA memory issues print(f"Using device: {device}") # Preload models try: transcriber = pipeline("automatic-speech-recognition", model="openai/whisper-large-v2", device=device) summarizer = pipeline("summarization", model="facebook/bart-large-cnn", device=device) except Exception as e: print(f"Error loading models: {e}. Make sure you have internet connectivity and sufficient resources.") transcriber = None summarizer = None # Google Drive API setup SCOPES = ['https://www.googleapis.com/auth/drive.readonly'] CLIENT_SECRET_FILE = 'client_secrets.json' # Relative path APPLICATION_NAME = 'MyMeetNotes' def get_credentials(): if not os.path.exists(CLIENT_SECRET_FILE): raise FileNotFoundError( "The 'client_secrets.json' file is missing. Please ensure it’s in the same directory as the script. See: " "https://developers.google.com/drive/api/v3/quickstart/python" ) creds = None if os.path.exists('token.json'): creds = credentials.Credentials.from_authorized_user_file('token.json', SCOPES) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES) creds = flow.run_local_server(port=0) with open('token.json', 'w') as token: token.write(creds.to_json()) return creds def list_google_meet_recordings(): try: creds = get_credentials() service = build('drive', 'v3', credentials=creds) results = service.files().list( pageSize=10, fields="nextPageToken, files(id, name, mimeType)", q="name contains 'Meeting recording' and mimeType contains 'video/'").execute() items = results.get('files', []) if not items: return ["No Google Meet recordings found."] return [f"{item['name']} (ID: {item['id']})" for item in items] except HttpError as error: return [f"An error occurred: {error}"] except Exception as e: return [f"An unexpected error occurred: {e}"] def download_google_meet_recording(file_id): try: creds = get_credentials() service = build('drive', 'v3', credentials=creds) file_name = f"temp_recording_{file_id}_{uuid.uuid4()}.mp4" # removed os.path.join(os.getcwd(), ...) for simplicity in local usage print(f"Downloading file ID: {file_id} to {file_name}") request = service.files().get_media(fileId=file_id) with open(file_name, 'wb') as fh: downloader = MediaIoBaseDownload(fh, request) done = False while not done: status, done = downloader.next_chunk() print(f"Download progress: {int(status.progress() * 100)}%") if os.path.exists(file_name): print(f"Download complete. File saved as: {file_name}") return file_name else: return f"Error: File '{file_name}' not found after download." except HttpError as error: return f"HTTP error during download: {error}" except Exception as e: return f"Unexpected error during download: {e}" def generate_meeting_notes(file_id): if transcriber is None or summarizer is None: return "Error: Models failed to load. Check your internet connection and resources." try: download_result = download_google_meet_recording(file_id) if isinstance(download_result, str) and "Error" in download_result: return download_result file_name = download_result if not os.path.exists(file_name): return f"Error: Downloaded file '{file_name}' not found." print(f"Extracting audio from {file_name}") video = mp.VideoFileClip(file_name) audio_file = f"temp_audio_{uuid.uuid4()}.wav" video.audio.write_audiofile(audio_file) print("Audio extraction complete.") print("Starting transcription...") transcription = transcriber(audio_file)["text"] print("Transcription complete.") print("Starting summarization...") summary = summarizer(transcription, max_length=1024, min_length=100, do_sample=False) meeting_notes = summary[0]["summary_text"] print("Summarization complete.") return meeting_notes except Exception as e: return f"Error in processing: {str(e)}" finally: try: if 'video' in locals() and video: # Check if video exists video.close() if 'audio_file' in locals() and os.path.exists(audio_file): os.remove(audio_file) if 'file_name' in locals() and os.path.exists(file_name): # Check if file_name exists os.remove(file_name) except Exception as cleanup_error: print(f"Cleanup error: {cleanup_error}") def launch_gradio(): with gr.Blocks() as iface: gr.Markdown("# Automatic Meeting Notes Generator from Google Meet") with gr.Row(): with gr.Column(): file_id_input = gr.Textbox(label="Google Meet Recording File ID", placeholder="Enter the Google Drive File ID") generate_button = gr.Button("Generate Notes") recording_list_button = gr.Button("List Recordings") with gr.Column(): output_text = gr.Textbox(label="Meeting Notes") recording_list = gr.Textbox(label="Available Recordings") generate_button.click(fn=generate_meeting_notes, inputs=file_id_input, outputs=output_text) recording_list_button.click(fn=list_google_meet_recordings, inputs=None, outputs=recording_list) iface.launch(debug=True) if __name__ == "__main__": launch_gradio()