lumaspeech-backend / ML /TextGenerator /image_integration.py
yasmine hemmati
Initial deployment: LumaSpeech Backend API with GPU support
d646f8a
Raw
History Blame Contribute Delete
7.79 kB
import os
import requests
import logging
import random
from typing import Dict, Any, Optional, List
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Get API key from environment
UNSPLASH_ACCESS_KEY = os.environ.get("UNSPLASH_ACCESS_KEY")
UNSPLASH_SECRET_KEY = os.environ.get("UNSPLASH_SECRET_KEY")
# Function to get the singleton instance
def get_image_provider() -> 'ImageIntegration':
return image_provider
class ImageIntegration:
"""
Class to handle image retrieval for articulation practice words
Uses Unsplash API to fetch relevant images
"""
def __init__(self):
self.has_unsplash_api = bool(UNSPLASH_ACCESS_KEY)
if self.has_unsplash_api:
logger.info("Unsplash API key found and configured")
else:
logger.warning("No Unsplash API key found. Using fallback image sources.")
def get_image_for_word(self, word: str) -> Dict[str, Any]:
"""
Get an image for a specific word
Args:
word: The word to find an image for
Returns:
Dictionary with image URL and attribution information
"""
if self.has_unsplash_api:
try:
return self._get_unsplash_image(word)
except Exception as e:
logger.error(f"Error getting Unsplash image for '{word}': {str(e)}")
return self._get_fallback_image(word)
else:
return self._get_fallback_image(word)
def _get_unsplash_image(self, query: str) -> Dict[str, Any]:
"""
Get an image from Unsplash API
Args:
query: Search term for the image
Returns:
Dictionary with image data
"""
try:
url = "https://api.unsplash.com/search/photos"
params = {
"query": query,
"per_page": 1,
"orientation": "landscape",
"content_filter": "high" # Only get high-quality images appropriate for all users
}
headers = {
"Authorization": f"Client-ID {UNSPLASH_ACCESS_KEY}"
}
response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
data = response.json()
if "results" in data and len(data["results"]) > 0:
result = data["results"][0]
# Extract relevant image data
image_data = {
"url": result["urls"]["regular"],
"thumb_url": result["urls"]["thumb"],
"attribution": f"Photo by {result['user']['name']} on Unsplash",
"attribution_url": result['user']['links']['html'],
"source": "unsplash"
}
return image_data
else:
# If no results, try a more general search
logger.info(f"No results for '{query}', trying more general search")
return self._get_general_category_image(query)
except Exception as e:
logger.error(f"Error in Unsplash API call: {str(e)}")
raise
def _get_general_category_image(self, word: str) -> Dict[str, Any]:
"""Get a more general category image when specific word has no results"""
# Map specific words to more general categories that are likely to have images
category_mapping = {
# Animals
"cat": "cat",
"dog": "dog",
"fish": "fish",
# Objects
"chair": "furniture",
"table": "furniture",
"lamp": "lighting",
# Food
"apple": "fruit",
"orange": "fruit",
"banana": "fruit",
# Default categories
"default": ["object", "item", "thing", "photo"]
}
# Try to find a category, or use defaults
category = category_mapping.get(word.lower())
if not category:
# Check if the word ends with common suffixes and map accordingly
if word.endswith(("ing", "tion", "ment")):
category = "action"
elif word.endswith(("ness", "ity", "ty")):
category = "concept"
else:
# Use a random default category
category = random.choice(category_mapping["default"])
if isinstance(category, list):
category = random.choice(category)
# Now try with the category
try:
url = "https://api.unsplash.com/search/photos"
params = {
"query": category,
"per_page": 30, # Get more results
"orientation": "landscape"
}
headers = {
"Authorization": f"Client-ID {UNSPLASH_ACCESS_KEY}"
}
response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
data = response.json()
if "results" in data and len(data["results"]) > 0:
# Select a random image from results
result = random.choice(data["results"])
image_data = {
"url": result["urls"]["regular"],
"thumb_url": result["urls"]["thumb"],
"attribution": f"Photo by {result['user']['name']} on Unsplash",
"attribution_url": result['user']['links']['html'],
"source": "unsplash"
}
return image_data
else:
return self._get_fallback_image(word)
except Exception as e:
logger.error(f"Error in general category search: {str(e)}")
return self._get_fallback_image(word)
def _get_fallback_image(self, word: str) -> Dict[str, Any]:
"""
Get a fallback image when API fails or is not available
Args:
word: The word to get an image for
Returns:
Dictionary with fallback image data
"""
# Use free placeholder services or default images
image_services = [
# Format: (url_template, attribution)
(f"https://source.unsplash.com/400x400/?{word}", "Image from Unsplash"),
(f"https://placehold.co/400x400/random/ffffff?text={word}", "Generated placeholder image"),
(f"https://dummyimage.com/400x400/3498db/ffffff&text={word}", "Generated placeholder image")
]
# Select a random service
service = random.choice(image_services)
return {
"url": service[0],
"attribution": service[1],
"source": "fallback"
}
def get_images_for_words(self, words: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""
Get images for a list of words
Args:
words: List of word dictionaries
Returns:
Words with added image data
"""
result = []
for word_item in words:
try:
word = word_item["word"]
image_data = self.get_image_for_word(word)
# Add image data to the word item
word_item["image"] = image_data
result.append(word_item)
except Exception as e:
logger.error(f"Error getting image for word '{word_item.get('word', '')}': {str(e)}")
# Add the word without an image
result.append(word_item)
return result
# Create singleton instance
image_provider = ImageIntegration()