MapMorph2 / mapmorph_agents /web_search_tools.py
CarlosHenr1que's picture
finish
420d49f
"""Web search tools for MapMorph agents."""
import re
from typing import Dict, Any, List
from agents import function_tool
# Curated database of popular brand colors
# Format: brand_name: [primary_color, secondary_color, ...]
BRAND_COLOR_DATABASE = {
# Tech companies
"google": ["#4285F4", "#34A853", "#FBBC05", "#EA4335"],
"facebook": ["#1877F2", "#F0F2F5"],
"meta": ["#0668E1", "#F0F2F5"],
"twitter": ["#1DA1F2", "#14171A", "#657786"],
"x": ["#000000", "#FFFFFF"],
"instagram": ["#E4405F", "#FCAF45", "#833AB4"],
"linkedin": ["#0A66C2", "#313335"],
"youtube": ["#FF0000", "#282828", "#FFFFFF"],
"spotify": ["#1DB954", "#191414"],
"apple": ["#000000", "#A6A6A6", "#F5F5F7"],
"microsoft": ["#00A4EF", "#F25022", "#7FBA00", "#FFB900"],
"amazon": ["#FF9900", "#146EB4"],
"netflix": ["#E50914", "#000000"],
"slack": ["#4A154B", "#36C5F0", "#2EB67D", "#ECB22E"],
"zoom": ["#2D8CFF", "#FFFFFF"],
"dropbox": ["#0061FF", "#1E1919"],
"github": ["#24292E", "#FFFFFF"],
"gitlab": ["#FC6D26", "#554488"],
# Brands
"nike": ["#000000", "#FFFFFF"],
"adidas": ["#000000", "#FFFFFF"],
"coca-cola": ["#F40009", "#FFFFFF"],
"pepsi": ["#004B93", "#E32934", "#FFFFFF"],
"starbucks": ["#00704A", "#FFFFFF"],
"mcdonald's": ["#FFC72C", "#DA291C"],
"mcdonals": ["#FFC72C", "#DA291C"], # Common misspelling
"subway": ["#00923F", "#FBAF3F"],
"kfc": ["#E4002B", "#FFFFFF"],
"ikea": ["#0051BA", "#FFCC00"],
"walmart": ["#0071CE", "#FFC220"],
"target": ["#CC0000", "#FFFFFF"],
"lego": ["#F6EC35", "#D11013", "#000000"],
# Automotive
"ferrari": ["#DC0000", "#000000"],
"lamborghini": ["#FFB81C", "#000000"],
"bmw": ["#1C69D4", "#FFFFFF"],
"audi": ["#BB0A30", "#000000"],
"toyota": ["#EB0A1E", "#FFFFFF"],
"tesla": ["#E82127", "#000000"],
# Fashion & Luxury
"gucci": ["#00693E", "#CE1126"],
"louis vuitton": ["#5B401F", "#FFFFFF"],
"chanel": ["#000000", "#FFFFFF"],
"hermes": ["#FF7A00", "#000000"],
"prada": ["#000000", "#FFFFFF"],
# Airlines
"delta": ["#003A70", "#C8102E"],
"united": ["#0066CC", "#FFFFFF"],
"american airlines": ["#0078D2", "#C8102E"],
"southwest": ["#304CB2", "#FFBF27"],
}
@function_tool
def search_brand_colors(brand_name: str) -> Dict[str, Any]:
"""Search for a brand's official color palette.
This tool searches a curated database of popular brand colors and returns
hex color codes. Use this when users mention brand names and want to apply
brand colors to the map.
Examples of when to use this:
- "Use Nike's brand colors"
- "Apply Coca-Cola colors to the map"
- "Make it look like the Spotify brand"
- "Use Apple's colors for the water"
Args:
brand_name: Name of the brand to search for (e.g., "Nike", "Coca-Cola", "Spotify")
Returns:
Dictionary containing:
- brand: Brand name
- colors: List of hex color codes found
- primary_color: Main brand color (if identifiable)
- found: Whether the brand was found in the database
- source: Information about where colors were found
"""
# Normalize brand name for search
normalized_name = brand_name.lower().strip()
# Search in database
if normalized_name in BRAND_COLOR_DATABASE:
colors = BRAND_COLOR_DATABASE[normalized_name]
return {
"brand": brand_name,
"colors": colors,
"primary_color": colors[0] if colors else None,
"found": True,
"source": "Curated brand color database",
"color_count": len(colors)
}
# Check for partial matches
for db_brand, colors in BRAND_COLOR_DATABASE.items():
if normalized_name in db_brand or db_brand in normalized_name:
return {
"brand": brand_name,
"colors": colors,
"primary_color": colors[0] if colors else None,
"found": True,
"source": f"Curated database (matched '{db_brand}')",
"color_count": len(colors)
}
# Brand not found
return {
"brand": brand_name,
"colors": [],
"primary_color": None,
"found": False,
"source": "Not found in database",
"suggestion": f"Brand '{brand_name}' not found. Try a different brand or specify colors directly."
}
@function_tool
def extract_colors_from_text(text: str) -> List[str]:
"""Extract hex color codes from text.
Use this helper tool to parse hex color codes from web search results,
documentation, or user input.
Args:
text: Text containing hex color codes (e.g., "#FF5733, #C70039, #900C3F")
Returns:
List of valid hex color codes found in the text
"""
# Regex pattern for hex colors: # followed by 3 or 6 hex digits
hex_pattern = r'#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\b'
matches = re.findall(hex_pattern, text)
# Normalize 3-digit hex to 6-digit
normalized = []
for match in matches:
if len(match) == 3:
# Expand #RGB to #RRGGBB
normalized.append(f"#{match[0]}{match[0]}{match[1]}{match[1]}{match[2]}{match[2]}")
else:
normalized.append(f"#{match}")
# Remove duplicates while preserving order
seen = set()
unique_colors = []
for color in normalized:
color_upper = color.upper()
if color_upper not in seen:
seen.add(color_upper)
unique_colors.append(color_upper)
return unique_colors
@function_tool
def suggest_layer_mapping_for_brand(
brand_colors: List[str],
brand_name: str = ""
) -> Dict[str, str]:
"""Suggest which brand colors should be applied to which map layers.
Use this tool after finding a brand's colors to intelligently map them
to appropriate map layers based on color psychology and aesthetics.
Args:
brand_colors: List of hex color codes from the brand palette
brand_name: Optional brand name for context
Returns:
Dictionary mapping layer IDs to suggested colors:
{
"water": "#HEXCODE",
"earth": "#HEXCODE",
"buildings": "#HEXCODE",
...
}
"""
if not brand_colors:
return {"error": "No brand colors provided"}
suggestions = {}
# Analyze colors by their properties
def color_brightness(hex_color: str) -> float:
"""Calculate perceived brightness (0-1) of a hex color."""
hex_color = hex_color.lstrip('#')
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
# Perceived brightness formula
return (0.299 * r + 0.587 * g + 0.114 * b) / 255
def is_blue_ish(hex_color: str) -> bool:
"""Check if color is blue-ish."""
hex_color = hex_color.lstrip('#')
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
return b > r and b > g
def is_green_ish(hex_color: str) -> bool:
"""Check if color is green-ish."""
hex_color = hex_color.lstrip('#')
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
return g > r and g > b
# Sort colors by brightness
sorted_colors = sorted(brand_colors, key=color_brightness)
darkest = sorted_colors[0]
lightest = sorted_colors[-1]
# Find blue-ish colors for water
blue_colors = [c for c in brand_colors if is_blue_ish(c)]
if blue_colors:
suggestions["water"] = blue_colors[0]
elif len(brand_colors) >= 2:
# Use second color if no blue found
suggestions["water"] = brand_colors[1] if len(brand_colors) > 1 else brand_colors[0]
# Find green-ish colors for parks/nature
green_colors = [c for c in brand_colors if is_green_ish(c)]
if green_colors:
suggestions["landuse"] = green_colors[0]
# Use lightest color for earth/background
suggestions["earth"] = lightest
# Use darkest or primary color for buildings
suggestions["buildings"] = darkest if len(brand_colors) > 2 else brand_colors[0]
# Use light color for roads
if color_brightness(lightest) > 0.7:
suggestions["roads"] = lightest
else:
suggestions["roads"] = "#FFFFFF" # Default to white if no light color
return suggestions