We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/talknerdytome-labs/facebook-ads-library-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
import os
import sys
import logging
import google.generativeai as genai
from google.generativeai.types import File
from typing import Optional, List, Dict, Any
# Set up logger
logger = logging.getLogger(__name__)
GEMINI_API_KEY = None
def get_gemini_api_key() -> str:
"""
Get Gemini API key from command line arguments or environment variable.
Caches the key in memory after first read.
Priority: command line argument > environment variable
Returns:
str: The Gemini API key.
Raises:
Exception: If no key is provided in command line arguments or environment.
"""
global GEMINI_API_KEY
if GEMINI_API_KEY is None:
# Try command line argument first
if "--gemini-api-key" in sys.argv:
token_index = sys.argv.index("--gemini-api-key") + 1
if token_index < len(sys.argv):
GEMINI_API_KEY = sys.argv[token_index]
logger.info(f"Using Gemini API key from command line arguments")
else:
raise Exception("--gemini-api-key argument provided but no key value followed it")
# Try environment variable
elif os.getenv("GEMINI_API_KEY"):
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
logger.info(f"Using Gemini API key from environment variable")
else:
raise Exception("Gemini API key must be provided via '--gemini-api-key' command line argument or 'GEMINI_API_KEY' environment variable")
return GEMINI_API_KEY
def configure_gemini() -> genai.GenerativeModel:
"""
Configure Gemini API with the API key and return a model instance.
Returns:
genai.GenerativeModel: Configured Gemini model instance for video analysis
"""
api_key = get_gemini_api_key()
genai.configure(api_key=api_key)
# Use Gemini 2.0 Flash for video analysis (more cost-effective than Pro)
model = genai.GenerativeModel('gemini-2.0-flash-exp')
logger.info("Gemini API configured successfully")
return model
def upload_video_to_gemini(video_path: str) -> File:
"""
Upload a video file to Gemini File API for analysis.
Args:
video_path: Path to the video file to upload
Returns:
genai.File: The uploaded file object for use in analysis
Raises:
Exception: If upload fails
"""
try:
# Upload video file
video_file = genai.upload_file(path=video_path)
# Wait for processing to complete
import time
while video_file.state.name == "PROCESSING":
time.sleep(2)
video_file = genai.get_file(video_file.name)
if video_file.state.name == "FAILED":
raise Exception(f"Video processing failed: {video_file.state}")
logger.info(f"Video uploaded successfully: {video_file.name}")
return video_file
except Exception as e:
logger.error(f"Failed to upload video to Gemini: {str(e)}")
raise
def analyze_video_with_gemini(model: genai.GenerativeModel, video_file: File, prompt: str) -> str:
"""
Analyze a video using Gemini with a custom prompt.
Args:
model: Configured Gemini model instance
video_file: Uploaded video file from Gemini File API
prompt: Analysis prompt for the video
Returns:
str: Analysis results from Gemini
Raises:
Exception: If analysis fails
"""
try:
# Generate analysis
response = model.generate_content([video_file, prompt])
if not response.text:
raise Exception("Gemini returned empty response")
logger.info("Video analysis completed successfully")
return response.text
except Exception as e:
logger.error(f"Video analysis failed: {str(e)}")
raise
def analyze_videos_batch_with_gemini(model: genai.GenerativeModel, video_files: List[File], prompt_template: str, video_contexts: List[Dict[str, Any]]) -> List[str]:
"""
Analyze multiple videos using Gemini in a single request for token efficiency.
Args:
model: Configured Gemini model instance
video_files: List of uploaded video files from Gemini File API
prompt_template: Base analysis prompt template
video_contexts: List of context dicts with brand_name, ad_id, etc. for each video
Returns:
List[str]: Analysis results for each video in order
Raises:
Exception: If batch analysis fails
"""
try:
if not video_files or len(video_files) != len(video_contexts):
raise Exception("Video files and contexts must have matching lengths")
# Create batch prompt with multiple videos
batch_prompt = f"""Analyze the following {len(video_files)} Facebook ad videos. For each video, provide analysis following this format:
{prompt_template}
Please analyze each video separately and clearly label each analysis as "VIDEO 1:", "VIDEO 2:", etc.
"""
# Add context information for each video
for i, context in enumerate(video_contexts, 1):
brand_info = f" (Brand: {context.get('brand_name', 'Unknown')})" if context.get('brand_name') else ""
ad_info = f" (Ad ID: {context.get('ad_id', 'Unknown')})" if context.get('ad_id') else ""
batch_prompt += f"VIDEO {i}{brand_info}{ad_info}:\n"
# Combine all video files with the prompt
content_parts = [batch_prompt] + video_files
# Generate batch analysis
response = model.generate_content(content_parts)
if not response.text:
raise Exception("Gemini returned empty response for batch analysis")
# Split response by video markers
analysis_text = response.text
video_analyses = []
# Parse individual video analyses
for i in range(1, len(video_files) + 1):
video_marker = f"VIDEO {i}:"
next_marker = f"VIDEO {i + 1}:" if i < len(video_files) else None
start_idx = analysis_text.find(video_marker)
if start_idx == -1:
logger.warning(f"Could not find analysis for VIDEO {i}")
video_analyses.append(f"Analysis not found in batch response for video {i}")
continue
start_idx += len(video_marker)
if next_marker:
end_idx = analysis_text.find(next_marker)
individual_analysis = analysis_text[start_idx:end_idx].strip() if end_idx != -1 else analysis_text[start_idx:].strip()
else:
individual_analysis = analysis_text[start_idx:].strip()
video_analyses.append(individual_analysis)
logger.info(f"Batch video analysis completed successfully for {len(video_files)} videos")
return video_analyses
except Exception as e:
logger.error(f"Batch video analysis failed: {str(e)}")
raise
def upload_videos_batch_to_gemini(video_paths: List[str]) -> List[File]:
"""
Upload multiple video files to Gemini File API for batch analysis.
Args:
video_paths: List of paths to video files to upload
Returns:
List[genai.File]: List of uploaded file objects for use in analysis
Raises:
Exception: If any upload fails
"""
uploaded_files = []
failed_uploads = []
try:
for i, video_path in enumerate(video_paths):
try:
# Upload video file
video_file = genai.upload_file(path=video_path)
# Wait for processing to complete
import time
while video_file.state.name == "PROCESSING":
time.sleep(2)
video_file = genai.get_file(video_file.name)
if video_file.state.name == "FAILED":
failed_uploads.append(f"Video {i+1}: {video_file.state}")
continue
uploaded_files.append(video_file)
logger.info(f"Video {i+1} uploaded successfully: {video_file.name}")
except Exception as e:
failed_uploads.append(f"Video {i+1}: {str(e)}")
logger.error(f"Failed to upload video {i+1} at {video_path}: {str(e)}")
if failed_uploads:
error_msg = f"Some video uploads failed: {'; '.join(failed_uploads)}"
if not uploaded_files: # All uploads failed
raise Exception(error_msg)
else: # Partial failure
logger.warning(error_msg)
return uploaded_files
except Exception as e:
# Cleanup any successfully uploaded files on total failure
for uploaded_file in uploaded_files:
try:
cleanup_gemini_file(uploaded_file.name)
except:
pass
raise
def cleanup_gemini_files_batch(file_names: List[str]):
"""
Delete multiple files from Gemini File API to free up storage.
Args:
file_names: List of file names to delete
"""
for file_name in file_names:
try:
genai.delete_file(file_name)
logger.info(f"Cleaned up Gemini file: {file_name}")
except Exception as e:
logger.warning(f"Failed to cleanup Gemini file {file_name}: {str(e)}")
def cleanup_gemini_file(file_name: str):
"""
Delete a file from Gemini File API to free up storage.
Args:
file_name: Name of the file to delete
"""
try:
genai.delete_file(file_name)
logger.info(f"Cleaned up Gemini file: {file_name}")
except Exception as e:
logger.warning(f"Failed to cleanup Gemini file {file_name}: {str(e)}")