meeting-summarizer / utils /llm_analysis.py
devsu's picture
Add initial implementation of Meeting Summarizer web app
164d23a
Raw
History Blame Contribute Delete
4.45 kB
"""
Module for analyzing meeting text using GPT-4o-mini.
Extracts summary, topics and keywords from text.
"""
import json
import logging
from typing import Dict, List, Optional
try:
from openai import OpenAI
except ImportError:
OpenAI = None
# Configurazione logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def analyze_meeting(text: str, api_key: str) -> Optional[Dict]:
"""
Analyze meeting text using GPT-4o-mini.
Args:
text (str): Meeting text to analyze
api_key (str): OpenAI API key
Returns:
Optional[Dict]: Dictionary with summary, topics, keywords or None if error
"""
if not text or not text.strip():
logger.error("Empty text provided for analysis")
return None
if not api_key:
logger.error("OpenAI API key not provided")
return None
if OpenAI is None:
logger.error("OpenAI not installed. Install with: pip install openai")
return None
try:
# Initialize OpenAI client
client = OpenAI(api_key=api_key)
# Structured prompt for analysis
prompt = f"""
Analyze the following meeting text and provide a response in JSON format with the following keys:
1. "summary": A comprehensive and detailed summary of the meeting (minimum 200 words)
2. "topics": A list of 5-8 main topics discussed in the meeting
3. "keywords": A list of 10-15 relevant keywords
Meeting text:
{text}
Respond ONLY with the requested JSON, without any additional text.
"""
logger.info("Sending request to GPT-4o-mini...")
# API call
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are an expert assistant in meeting analysis. Always provide responses in valid JSON format."},
{"role": "user", "content": prompt}
],
max_tokens=2000,
temperature=0.3
)
# Extract response content
content = response.choices[0].message.content.strip()
# Clean content from any markdown or extra text
if content.startswith("```json"):
content = content[7:]
if content.endswith("```"):
content = content[:-3]
# Parse JSON
try:
result = json.loads(content)
# Structure validation
required_keys = ["summary", "topics", "keywords"]
if not all(key in result for key in required_keys):
logger.error("Invalid JSON structure: missing keys")
return None
# Type validation
if not isinstance(result["summary"], str):
logger.error("Summary must be a string")
return None
if not isinstance(result["topics"], list):
logger.error("Topics must be a list")
return None
if not isinstance(result["keywords"], list):
logger.error("Keywords must be a list")
return None
logger.info("Analysis completed successfully")
return result
except json.JSONDecodeError as e:
logger.error(f"JSON parsing error: {str(e)}")
logger.error(f"Received content: {content}")
return None
except Exception as e:
logger.error(f"Error during meeting analysis: {str(e)}")
return None
def format_analysis_for_display(analysis: Dict) -> Dict[str, str]:
"""
Format analysis for display in Gradio.
Args:
analysis (Dict): Analysis result
Returns:
Dict[str, str]: Dictionary formatted for display
"""
if not analysis:
return {
"summary": "Error in analysis",
"topics": "Error in analysis",
"keywords": "Error in analysis"
}
# Format topics as markdown list
topics_md = "\n".join([f"- {topic}" for topic in analysis.get("topics", [])])
# Format keywords as markdown list
keywords_md = "\n".join([f"- {keyword}" for keyword in analysis.get("keywords", [])])
return {
"summary": analysis.get("summary", "Summary not available"),
"topics": topics_md,
"keywords": keywords_md
}