🔍 Code Extractor

function generate_minutes

Maturity: 56

Flask route handler that processes uploaded meeting transcripts and optional supporting documents to generate structured meeting minutes using AI, with configurable output styles and validation.

File:
/tf/active/vicechatdev/leexi/app.py
Lines:
136 - 294
Complexity:
complex

Purpose

This function serves as the main endpoint for a web application that generates meeting minutes. It handles file uploads (transcript, PowerPoint, previous reports), validates inputs, processes documents through an AI-powered generator with customizable parameters (rigor level, detail level, action focus, output style), handles potential output truncation, validates the generated content, saves the results, and returns both HTML and Markdown formatted minutes. It's designed for teams needing automated, consistent meeting documentation with quality controls.

Source Code

def generate_minutes():
    """Generate meeting minutes based on form input"""
    try:
        # Get form data
        meeting_title = request.form.get('meeting_title', 'Development Team Meeting')
        model = request.form.get('model', 'gpt-4o')
        user_instructions = request.form.get('user_instructions', '')
        
        # Get configuration options
        rigor_level = request.form.get('rigor_level', 'balanced')
        detail_level = request.form.get('detail_level', 'comprehensive')
        action_focus = request.form.get('action_focus', 'standard')
        output_style = request.form.get('output_style', 'professional')
        
        # Handle file uploads
        uploaded_files = {}
        
        # Transcript file (required)
        if 'transcript' not in request.files:
            return jsonify({'error': 'No transcript file provided'}), 400
        
        transcript_file = request.files['transcript']
        if transcript_file.filename == '':
            return jsonify({'error': 'No transcript file selected'}), 400
        
        if transcript_file and allowed_file(transcript_file.filename):
            filename = secure_filename(transcript_file.filename)
            transcript_path = UPLOAD_FOLDER / f"transcript_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{filename}"
            transcript_file.save(transcript_path)
            uploaded_files['transcript'] = transcript_path
        else:
            return jsonify({'error': 'Invalid transcript file type'}), 400
        
        # PowerPoint file (optional)
        powerpoint_path = None
        if 'powerpoint' in request.files:
            powerpoint_file = request.files['powerpoint']
            if powerpoint_file and powerpoint_file.filename != '' and allowed_file(powerpoint_file.filename):
                filename = secure_filename(powerpoint_file.filename)
                powerpoint_path = UPLOAD_FOLDER / f"powerpoint_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{filename}"
                powerpoint_file.save(powerpoint_path)
                uploaded_files['powerpoint'] = powerpoint_path
        
        # Previous reports (optional, multiple files)
        previous_reports = []
        if 'previous_reports' in request.files:
            files = request.files.getlist('previous_reports')
            for file in files:
                if file and file.filename != '' and allowed_file(file.filename):
                    filename = secure_filename(file.filename)
                    file_path = UPLOAD_FOLDER / f"previous_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{filename}"
                    file.save(file_path)
                    previous_reports.append(file_path)
        
        # Initialize generator
        generator = EnhancedMeetingMinutesGenerator(model=model)
        
        # Load transcript
        with open(uploaded_files['transcript'], 'r', encoding='utf-8') as f:
            transcript = f.read()
        
        # Process PowerPoint if provided
        ppt_content = None
        if powerpoint_path:
            ppt_content = generator.process_powerpoint_content(str(powerpoint_path))
        
        # Extract previous reports summary
        previous_reports_summary = ""
        if previous_reports:
            previous_reports_summary = extract_previous_reports_summary([str(p) for p in previous_reports])
        
        # Generate enhanced meeting minutes with configuration
        minutes = generator.generate_meeting_minutes_with_config(
            transcript=transcript,
            ppt_content=ppt_content,
            meeting_title=meeting_title,
            previous_reports_summary=previous_reports_summary,
            user_instructions=user_instructions,
            rigor_level=rigor_level,
            detail_level=detail_level,
            action_focus=action_focus,
            output_style=output_style
        )
        
        # Handle potential truncation with automatic regeneration
        minutes = handle_potential_truncation(
            generator, 
            minutes,
            transcript=transcript,
            ppt_content=ppt_content,
            meeting_title=meeting_title,
            previous_reports_summary=previous_reports_summary,
            user_instructions=user_instructions,
            rigor_level=rigor_level,
            detail_level=detail_level,
            action_focus=action_focus,
            output_style=output_style
        )
        
        # Check for remaining validation issues
        validation_notes = []
        if "## Meeting Agenda" in minutes and "## Meeting Discussion by Agenda Item" in minutes:
            agenda_section = minutes.split("## Meeting Agenda")[1].split("##")[0]
            agenda_items = [line.strip() for line in agenda_section.split('\n') if line.strip() and any(line.strip().startswith(f'{i}.') for i in range(1, 10))]
            
            discussion_section = minutes.split("## Meeting Discussion by Agenda Item")[1].split("## Action Items")[0] if "## Action Items" in minutes else minutes.split("## Meeting Discussion by Agenda Item")[1]
            discussion_items = [line.strip() for line in discussion_section.split('\n') if line.strip().startswith('###')]
            
            if len(agenda_items) > len(discussion_items):
                validation_notes.append(f"⚠️ WARNING: Agenda lists {len(agenda_items)} items but only {len(discussion_items)} discussion sections generated.")
                validation_notes.append("Output may be incomplete. Consider regenerating with modified instructions.")
        
        # Add validation warnings to the output if needed
        if validation_notes:
            minutes += "\n\n## Generation Validation Warnings\n"
            for note in validation_notes:
                minutes += f"- {note}\n"
        
        # Save the generated report
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        report_filename = f"meeting_minutes_{timestamp}.md"
        report_path = REPORTS_FOLDER / report_filename
        
        with open(report_path, 'w', encoding='utf-8') as f:
            f.write(minutes)
        
        # Convert to HTML for display
        html_content = markdown.markdown(minutes, extensions=['tables', 'fenced_code'])
        
        # Store session data for potential regeneration
        session_data = {
            'transcript_path': str(uploaded_files['transcript']),
            'powerpoint_path': str(powerpoint_path) if powerpoint_path else None,
            'previous_reports': [str(p) for p in previous_reports],
            'meeting_title': meeting_title,
            'model': model,
            'user_instructions': user_instructions,
            'rigor_level': rigor_level,
            'detail_level': detail_level,
            'action_focus': action_focus,
            'output_style': output_style,
            'report_path': str(report_path)
        }
        
        session_file = REPORTS_FOLDER / f"session_{timestamp}.json"
        with open(session_file, 'w') as f:
            json.dump(session_data, f)
        
        return jsonify({
            'success': True,
            'html_content': html_content,
            'markdown_content': minutes,
            'report_path': str(report_path),
            'session_id': timestamp
        })
    
    except Exception as e:
        logger.error(f"Error generating minutes: {str(e)}")
        return jsonify({'error': f'Error generating minutes: {str(e)}'}), 500

Return Value

Returns a Flask JSON response. On success (200): {'success': True, 'html_content': string (HTML-formatted minutes), 'markdown_content': string (raw Markdown minutes), 'report_path': string (file path to saved report), 'session_id': string (timestamp identifier)}. On error (400/500): {'error': string (error message)} with appropriate HTTP status code.

Dependencies

  • flask
  • werkzeug
  • markdown
  • openai
  • pathlib
  • datetime
  • json
  • logging
  • tempfile
  • os

Required Imports

from flask import Flask, render_template, request, jsonify, send_file, flash, redirect, url_for
from werkzeug.utils import secure_filename
import markdown
import logging
from datetime import datetime
from pathlib import Path
import json
import os
import tempfile
import openai
from enhanced_meeting_minutes_generator import EnhancedMeetingMinutesGenerator
from document_extractor import DocumentExtractor

Usage Example

# Flask application setup
from flask import Flask, request, jsonify
from pathlib import Path
import logging

app = Flask(__name__)
UPLOAD_FOLDER = Path('./uploads')
REPORTS_FOLDER = Path('./reports')
UPLOAD_FOLDER.mkdir(exist_ok=True)
REPORTS_FOLDER.mkdir(exist_ok=True)
logger = logging.getLogger(__name__)

# Helper functions (simplified)
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in {'txt', 'md', 'pptx', 'pdf'}

def extract_previous_reports_summary(paths):
    return "Summary of previous reports"

def handle_potential_truncation(generator, minutes, **kwargs):
    return minutes

@app.route('/generate', methods=['POST'])
def generate_minutes():
    # Function implementation here
    pass

# Client-side usage (JavaScript/HTML form)
# <form method="POST" action="/generate" enctype="multipart/form-data">
#   <input type="text" name="meeting_title" value="Team Sync">
#   <select name="model"><option value="gpt-4o">GPT-4o</option></select>
#   <select name="rigor_level"><option value="balanced">Balanced</option></select>
#   <input type="file" name="transcript" required>
#   <input type="file" name="powerpoint">
#   <button type="submit">Generate Minutes</button>
# </form>

if __name__ == '__main__':
    app.run(debug=True)

Best Practices

  • Ensure UPLOAD_FOLDER and REPORTS_FOLDER directories exist and have write permissions before starting the application
  • Configure proper file size limits in Flask to prevent memory issues with large uploads
  • Implement rate limiting to prevent API abuse and excessive OpenAI API costs
  • Set up proper error logging and monitoring for production environments
  • Clean up old uploaded files periodically to prevent disk space issues
  • Validate and sanitize all user inputs, especially user_instructions, to prevent prompt injection
  • Consider implementing authentication/authorization before deploying to production
  • Set appropriate timeouts for AI generation calls to prevent hanging requests
  • Store session files with expiration and implement cleanup routines
  • Use environment variables for sensitive configuration like API keys
  • Test with various file types and sizes to ensure robust error handling
  • Consider implementing async processing for large files to improve user experience
  • Add CORS configuration if the API will be accessed from different domains

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function regenerate_minutes 81.5% similar

    Flask route handler that regenerates meeting minutes from a previous session using modified instructions, model selection, and configuration parameters.

    From: /tf/active/vicechatdev/leexi/app.py
  • class MeetingMinutesGenerator 72.5% similar

    A class that generates professional meeting minutes from meeting transcripts using OpenAI's GPT-4o model, with capabilities to parse metadata, extract action items, and format output.

    From: /tf/active/vicechatdev/meeting_minutes_generator.py
  • function test_web_ui 70.6% similar

    Integration test function that validates a Flask web UI for meeting minutes generation by testing file upload, generation, and regeneration endpoints with sample transcript and PowerPoint files.

    From: /tf/active/vicechatdev/leexi/test_ui.py
  • function main_v27 70.3% similar

    Entry point function that orchestrates the process of loading a meeting transcript, generating structured meeting minutes using OpenAI's GPT-4o API, and saving the output to a file.

    From: /tf/active/vicechatdev/meeting_minutes_generator.py
  • class MeetingMinutesGenerator_v1 70.3% similar

    A class that generates professional meeting minutes from meeting transcripts using either OpenAI's GPT-4o or Google's Gemini AI models.

    From: /tf/active/vicechatdev/advanced_meeting_minutes_generator.py
← Back to Browse