| | import base64 |
| | import requests |
| | from PIL import Image |
| | import io |
| | import json |
| | import logging |
| | import json |
| | import pandas as pd |
| | import re |
| |
|
| |
|
| | IMAGE_ANALYSES_KEY = "Image Analyses" |
| | |
| | logging.basicConfig(level=logging.INFO) |
| |
|
| | import os |
| | api_key = os.environ.get("OPENAI_API_KEY") |
| |
|
| | |
| | def encode_image(image_path): |
| | try: |
| | with Image.open(image_path) as img: |
| | img.thumbnail((800, 800)) |
| | buffer = io.BytesIO() |
| | img.save(buffer, format="JPEG", quality=85) |
| | encoded_image = base64.b64encode(buffer.getvalue()).decode('utf-8') |
| | return encoded_image |
| | except Exception as e: |
| | logging.error(f"Failed to encode image {image_path}: {e}") |
| | return None |
| |
|
| | |
| | def get_image_dimensions(image_path): |
| | try: |
| | with Image.open(image_path) as img: |
| | return img.size |
| | except Exception as e: |
| | logging.error(f"Failed to get dimensions for image {image_path}: {e}") |
| | return (0, 0) |
| |
|
| | |
| | image_paths = [ |
| | "data/competitor/image1.jpeg", |
| | "data/competitor/image2.jpeg", |
| | "data/competitor/image3.jpeg", |
| | "data/competitor/image4.jpeg", |
| | "data/competitor/image5.jpeg", |
| | "data/competitor/image6.jpeg" |
| | ] |
| |
|
| | |
| | headers = { |
| | "Content-Type": "application/json", |
| | "Authorization": f"Bearer {api_key}" |
| | } |
| |
|
| | |
| | competitor_information = """ |
| | The competitor is a leading brand in the digital marketing space known for its consistent visual branding and innovative designs on social media. They target a tech-savvy audience aged 20-35 with a focus on modern aesthetics, engaging storytelling, and minimalist yet powerful branding. |
| | """ |
| |
|
| | system_message = """ |
| | Analyze the branding, content marketing, and social media marketing effectiveness of a company for the provided Instagram post image. |
| | Evaluate it based on the following criteria and return a detailed JSON structure. Each criterion should have an individual score (0-10), and the total score for the category should be the average of its criteria. |
| | Give 9 or above only when it's extraordinary. Industry standard 7-8 |
| | ### Categories and Definitions: |
| | |
| | #### Branding: |
| | - **Logo Placement**: Is the logo perfectly sized, clearly visible, and well-positioned without being intrusive? |
| | - **Brand Colors**: Are brand colors used consistently and without deviations? |
| | - **Typography**: Are the fonts aligned with the brand identity, consistent in style, and visually appealing? |
| | - **Brand Identity**: Does the post effectively reflect the brand's unique persona and messaging? |
| | - **Visual Hierarchy**: Are key elements prioritized effectively to guide the viewer’s attention? |
| | - **Template Consistency**: Are templates consistent with previous posts, reflecting a uniform design approach? |
| | - **Messaging Alignment**: Is the brand messaging clear, consistent, and reflective of the brand's tone? |
| | - **Subtle Branding**: Does the branding strike the right balance (not overly subtle or excessive)? |
| | - **Overbranding**: Does the post avoid overwhelming and distracting brand elements? |
| | - **Creative Variations**: Are there innovative and creative design variations in the post? |
| | |
| | #### Content Marketing: |
| | - **Content Visibility**: Is the primary content clear and highlighted effectively? |
| | - **Engagement Cues**: Are clear and compelling calls-to-action (CTAs) present and engaging? |
| | - **Information Overload**: Does the post avoid over-saturated visuals or excessive text? |
| | - **Storytelling**: Does the post convey a relevant and engaging narrative that resonates with the audience? |
| | - **Content Variety**: Are the posts diverse and free of monotonous or repetitive elements? |
| | - **Typography Consistency**: Is the typography visually attractive and consistent throughout the design? |
| | - **Aesthetic Coherence**: Do all elements harmonize to create a visually appealing composition? |
| | - **Content Relevance**: Is the content relevant to the brand and its target audience? |
| | - **Stock Elements**: Does the design avoid excessive use of generic or stock imagery? |
| | |
| | #### Social Media Marketing: |
| | - **Font Size**: Are fonts appropriately sized and legible on various screen sizes? |
| | - **Visibility of Text**: Is the text easy to read, with proper contrast, placement, and spacing? |
| | - **Logo Placement**: Does the logo placement avoid disrupting the design's aesthetic appeal? |
| | - **Consistency**: Does the post maintain design cohesion across elements? |
| | - **Alignment**: Are elements aligned professionally, creating a balanced and clean layout? |
| | - **Aesthetic Appeal**: Is the overall design visually engaging and suitable for the platform? |
| | - **Brand Elements**: Are brand assets (like logos, icons, or visuals) used effectively and sparingly? |
| | - **Repetitiveness**: Does the design avoid repetitive themes and offer fresh creative ideas? |
| | |
| | ### Output JSON Format: |
| | ### Only return the following format strictly |
| | |
| | { |
| | "Branding Score": total_avg_score, explanation. |
| | "criteria_name": score, explanation. |
| | "criteria_name": score, explanation. |
| | |
| | "Content Marketing Score": total_avg_score, explanation. |
| | "criteria_name": score, explanation. |
| | "criteria_name": score, explanation. |
| | |
| | "Social Media Marketing Score": total_avg_score, explanation. |
| | "criteria_name": score, explanation. |
| | "criteria_name": score, explanation. |
| | } |
| | """ |
| |
|
| | |
| | def request_analysis(system_message, user_message, model="gpt-4o-mini", max_tokens=1500): |
| | payload = { |
| | "model": model, |
| | "messages": [ |
| | {"role": "system", "content": system_message}, |
| | {"role": "user", "content": user_message} |
| | ], |
| | "max_tokens": max_tokens |
| | } |
| | logging.debug(f"Payload Sent: {json.dumps(payload, indent=4)}") |
| | response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload) |
| |
|
| | if response.status_code == 200: |
| | try: |
| | return response.json().get("choices", [{}])[0].get("message", {}).get("content", "Unexpected response format") |
| | except Exception as e: |
| | logging.error(f"Error parsing response: {e}") |
| | logging.debug(f"Raw Response: {response.text}") |
| | return "Error parsing the response." |
| | else: |
| | logging.error(f"API Error: {response.status_code}, {response.text}") |
| | return "Error with the API request." |
| |
|
| | |
| | output_structure = { |
| | IMAGE_ANALYSES_KEY: [] |
| | } |
| |
|
| | |
| | for image_path in image_paths: |
| | base64_image = encode_image(image_path) |
| | if not base64_image: |
| | output_structure[IMAGE_ANALYSES_KEY].append({ |
| | "Image": image_path, |
| | "Analysis": "Failed to encode image." |
| | }) |
| | continue |
| |
|
| | width, height = get_image_dimensions(image_path) |
| | user_message = f""" |
| | Company Information: {competitor_information} |
| | Analyze the Instagram post with dimensions {width}x{height} pixels. Image data: {base64_image} |
| | """ |
| |
|
| | try: |
| | analysis_result = request_analysis(system_message, user_message) |
| | try: |
| | |
| | parsed_result = json.loads(analysis_result) |
| | except json.JSONDecodeError: |
| | logging.warning(f"Response not in expected JSON format for {image_path}: {analysis_result}") |
| | parsed_result = {"Raw Response": analysis_result} |
| |
|
| | output_structure[IMAGE_ANALYSES_KEY].append({ |
| | "Image": image_path, |
| | "Analysis": parsed_result |
| | }) |
| | except Exception as err: |
| | logging.error(f"Error analyzing image {image_path}: {err}") |
| | output_structure[IMAGE_ANALYSES_KEY].append({ |
| | "Image": image_path, |
| | "Analysis": "Error analyzing the image." |
| | }) |
| |
|
| | |
| | with open("Output_File/json/competitor_analysis.json", "w") as f: |
| | json.dump(output_structure, f, indent=4) |
| |
|
| | logging.info("Analysis completed and saved to competitor_analysis.json") |
| |
|
| |
|
| | def json_to_excel(json_file, excel_file): |
| | """ |
| | Parse the JSON file and convert it to an Excel file with structured scores and raw JSON responses. |
| | |
| | Args: |
| | json_file (str): Path to the input JSON file. |
| | excel_file (str): Path to the output Excel file. |
| | """ |
| | |
| | with open(json_file, 'r') as file: |
| | data = json.load(file) |
| |
|
| | |
| | structured_data = [] |
| |
|
| | |
| | score_pattern = r'"([a-zA-Z\s]+)":\s*(\d+),' |
| |
|
| | |
| | for analysis in data.get("Image Analyses", []): |
| | |
| | image = analysis.get("Image", "Unknown") |
| |
|
| | |
| | raw_response = analysis.get("Analysis", {}).get("Raw Response", "") |
| |
|
| | |
| | image_data = {"Image": image, "Raw JSON Response": raw_response} |
| |
|
| | |
| | matches = re.findall(score_pattern, raw_response) |
| | for criterion, score in matches: |
| | image_data[criterion.strip()] = int(score) |
| |
|
| | |
| | structured_data.append(image_data) |
| |
|
| | |
| | df = pd.DataFrame(structured_data) |
| |
|
| | |
| | df.to_excel(excel_file, index=False) |
| | print(f"Data successfully written to {excel_file}") |
| | |
| | json_file_path = "Output_File/json/competitor_analysis.json" |
| | excel_file_path = "Output_File/excel/competitor_analysis.xlsx" |
| | json_to_excel(json_file_path, excel_file_path) |
| |
|