From 4e5aca4ca6abe26cb39657478b5230fe0a2806fa Mon Sep 17 00:00:00 2001 From: haritha1313 Date: Wed, 22 Oct 2025 14:17:17 -0700 Subject: [PATCH 1/2] algorithmia change --- algorithmia.py | 423 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 375 insertions(+), 48 deletions(-) diff --git a/algorithmia.py b/algorithmia.py index e608ce1..ba954cd 100644 --- a/algorithmia.py +++ b/algorithmia.py @@ -7,58 +7,385 @@ import matplotlib.pyplot as plt, mpld3 from matplotlib import colors import matplotlib.patches as mpatches +from typing import Dict, List, Optional, Tuple +from dataclasses import dataclass +from enum import Enum +import logging -emot_list= list() +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) -def get_emotion(): - print("Getting emotion...") - # API call - input = bytearray(open("snapshots/pic.png", "rb").read()) - client = Algorithmia.client('api-key') - algo = client.algo('deeplearning/EmotionRecognitionCNNMBP/1.0.1') - op = (algo.pipe(input).result)["results"] +# Global emotion history storage +emot_list = list() - # Returned from API call - - if(op==[]): - current = "Neutral" - else: - emotion = ((op[0])["emotions"]) - analyze = dict() - - for emo in emotion: - analyze[str(emo["label"])] = float(emo["confidence"]) - current = max(analyze, key=analyze.get) - - # Color code emotions - emotion_color_dict = {'Neutral':11 , 'Sad':31 , 'Disgust':51 , 'Fear':61 , 'Surprise':41, 'Happy':21, 'Angry':1} - emot_list.append(emotion_color_dict[current]) - print(emot_list) - - return current - -def get_playlist(): - current = get_emotion() - #get playlist from emotion - - with open("test.txt", "rb") as fp: - songnames = pickle.load(fp, encoding='latin1') - songlist = {1: [1,170], 2:[171,334], 3:[335,549], 4:[550, 740], 5:[741,903]} - if ((current == "Anger") | (current == "Fear")): - cluster_def = [[5, 2], [3, 7], [2, 12]] - elif(current == "Sad"): - cluster_def = [[3, 4], [4, 4], [2, 13]] - elif((current == "Neutral") | (current == "Disgust") | (current == "Surprise")): - cluster_def = [[3, 2], [4, 5], [2, 7], [1, 5]] +class EmotionType(Enum): + """Enumeration of supported emotion types""" + ANGRY = "Angry" + NEUTRAL = "Neutral" + HAPPY = "Happy" + SAD = "Sad" + SURPRISE = "Surprise" + DISGUST = "Disgust" + FEAR = "Fear" + +@dataclass +class EmotionResult: + """Data class for emotion detection results""" + emotion: EmotionType + confidence: float + all_emotions: Dict[str, float] + color_code: int + +def _get_emotion_color_mapping() -> Dict[str, int]: + """ + Get the color code mapping for emotions. + + Returns: + Dictionary mapping emotion names to color codes + """ + return { + 'Neutral': 11, + 'Sad': 31, + 'Disgust': 51, + 'Fear': 61, + 'Surprise': 41, + 'Happy': 21, + 'Angry': 1 + } + +def _call_emotion_api(image_path: str = "snapshots/pic.png") -> Dict: + """ + Make API call to emotion recognition service. + + Args: + image_path: Path to the image file + + Returns: + API response dictionary + + Raises: + FileNotFoundError: If image file doesn't exist + RuntimeError: If API call fails + """ + try: + with open(image_path, "rb") as img_file: + input_data = bytearray(img_file.read()) + + client = Algorithmia.client('api-key') + algo = client.algo('deeplearning/EmotionRecognitionCNNMBP/1.0.1') + result = algo.pipe(input_data).result + + return result + except FileNotFoundError as e: + logger.error(f"Image file not found: {image_path}") + raise + except Exception as e: + logger.error(f"API call failed: {str(e)}") + raise RuntimeError(f"Emotion recognition API failed: {str(e)}") + +def _parse_emotion_results(api_response: Dict) -> EmotionResult: + """ + Parse API response and extract emotion information. + + Args: + api_response: Raw API response + + Returns: + EmotionResult object with parsed data + """ + results = api_response.get("results", []) + + # Handle no detection case + if not results: + logger.info("No emotions detected, defaulting to Neutral") + color_mapping = _get_emotion_color_mapping() + return EmotionResult( + emotion=EmotionType.NEUTRAL, + confidence=1.0, + all_emotions={"Neutral": 1.0}, + color_code=color_mapping['Neutral'] + ) + + # Extract emotion confidences + emotions_data = results[0].get("emotions", []) + emotion_scores = {} + + for emotion_item in emotions_data: + label = str(emotion_item["label"]) + confidence = float(emotion_item["confidence"]) + emotion_scores[label] = confidence + + # Find dominant emotion + if not emotion_scores: + dominant_emotion = "Neutral" + confidence_score = 1.0 else: - cluster_def = [[2, 10], [4, 5], [1, 6]] - - playlist = list() - for sets in cluster_def: - for i in range(sets[1]): - ss = random.randint(songlist[sets[0]][0], songlist[sets[0]][1]); - playlist.append(str(ss).zfill(3)+".mp3_"+songnames[ss]); - return playlist + dominant_emotion = max(emotion_scores.items(), key=lambda x: x[1])[0] + confidence_score = emotion_scores[dominant_emotion] + + # Get color code + color_mapping = _get_emotion_color_mapping() + color_code = color_mapping.get(dominant_emotion, 11) # Default to neutral color + + # Store in history + global emot_list + emot_list.append(color_code) + logger.info(f"Detected emotion: {dominant_emotion} (confidence: {confidence_score:.2f})") + logger.debug(f"Emotion history: {emot_list}") + + # Map to enum + try: + emotion_enum = EmotionType(dominant_emotion) + except ValueError: + emotion_enum = EmotionType.NEUTRAL + + return EmotionResult( + emotion=emotion_enum, + confidence=confidence_score, + all_emotions=emotion_scores, + color_code=color_code + ) + +def get_emotion(image_path: str = "snapshots/pic.png") -> str: + """ + Detect emotion from facial expression in image. + + This function uses deep learning to analyze facial expressions and + identify the dominant emotion. Results are stored in global history + for trend analysis. + + Args: + image_path: Path to image file containing face (default: snapshots/pic.png) + + Returns: + String name of detected emotion (e.g., 'Happy', 'Sad', 'Neutral') + + Raises: + FileNotFoundError: If image file doesn't exist + RuntimeError: If emotion detection fails + """ + logger.info(f"Getting emotion from: {image_path}") + + try: + # Call API + api_response = _call_emotion_api(image_path) + + # Parse results + emotion_result = _parse_emotion_results(api_response) + + # Return emotion name + return emotion_result.emotion.value + + except Exception as e: + logger.error(f"Error in emotion detection: {str(e)}") + # Return neutral on error + return EmotionType.NEUTRAL.value + +def get_emotion_detailed(image_path: str = "snapshots/pic.png") -> EmotionResult: + """ + Get detailed emotion detection results including all confidence scores. + + Args: + image_path: Path to image file + + Returns: + EmotionResult with full detection data + """ + api_response = _call_emotion_api(image_path) + return _parse_emotion_results(api_response) + +@dataclass +class MusicCluster: + """Configuration for music cluster selection""" + cluster_id: int + count: int + mood_category: str + +class PlaylistGenerator: + """ + Advanced playlist generation based on detected emotions. + + This class handles the complex logic of mapping emotions to music clusters + and generating personalized playlists. + """ + + # Song database configuration + SONG_CLUSTERS = { + 1: (1, 170), + 2: (171, 334), + 3: (335, 549), + 4: (550, 740), + 5: (741, 903) + } + + # Emotion to cluster mapping with weights + EMOTION_CLUSTER_MAPPING = { + "Angry": [ + MusicCluster(5, 2, "intense"), + MusicCluster(3, 7, "energetic"), + MusicCluster(2, 12, "powerful") + ], + "Fear": [ + MusicCluster(5, 2, "intense"), + MusicCluster(3, 7, "dark"), + MusicCluster(2, 12, "atmospheric") + ], + "Sad": [ + MusicCluster(3, 4, "melancholy"), + MusicCluster(4, 4, "reflective"), + MusicCluster(2, 13, "soothing") + ], + "Neutral": [ + MusicCluster(3, 2, "balanced"), + MusicCluster(4, 5, "moderate"), + MusicCluster(2, 7, "ambient"), + MusicCluster(1, 5, "light") + ], + "Disgust": [ + MusicCluster(3, 2, "edgy"), + MusicCluster(4, 5, "alternative"), + MusicCluster(2, 7, "experimental"), + MusicCluster(1, 5, "unusual") + ], + "Surprise": [ + MusicCluster(3, 2, "dynamic"), + MusicCluster(4, 5, "upbeat"), + MusicCluster(2, 7, "varied"), + MusicCluster(1, 5, "exciting") + ], + "Happy": [ + MusicCluster(2, 10, "joyful"), + MusicCluster(4, 5, "uplifting"), + MusicCluster(1, 6, "cheerful") + ] + } + + def __init__(self, song_database_path: str = "test.txt"): + """ + Initialize playlist generator. + + Args: + song_database_path: Path to pickled song database + """ + self.song_database_path = song_database_path + self._song_names = None + + def _load_song_database(self) -> Dict[int, str]: + """ + Load song names from database file. + + Returns: + Dictionary mapping song IDs to names + + Raises: + FileNotFoundError: If database file doesn't exist + """ + if self._song_names is None: + try: + with open(self.song_database_path, "rb") as fp: + self._song_names = pickle.load(fp, encoding='latin1') + logger.info(f"Loaded {len(self._song_names)} songs from database") + except FileNotFoundError: + logger.error(f"Song database not found: {self.song_database_path}") + raise + + return self._song_names + + def _select_song_from_cluster(self, cluster_id: int) -> Tuple[int, str]: + """ + Select a random song from specified cluster. + + Args: + cluster_id: ID of the music cluster + + Returns: + Tuple of (song_id, formatted_song_name) + """ + song_names = self._load_song_database() + cluster_range = self.SONG_CLUSTERS[cluster_id] + + song_id = random.randint(cluster_range[0], cluster_range[1]) + song_name = song_names[song_id] + formatted_name = f"{str(song_id).zfill(3)}.mp3_{song_name}" + + return song_id, formatted_name + + def generate_playlist(self, emotion: str, shuffle: bool = True) -> List[str]: + """ + Generate a playlist based on detected emotion. + + Args: + emotion: Detected emotion string + shuffle: Whether to shuffle the final playlist + + Returns: + List of song filenames + + Raises: + ValueError: If emotion is not recognized + """ + logger.info(f"Generating playlist for emotion: {emotion}") + + # Get cluster configuration for this emotion + if emotion not in self.EMOTION_CLUSTER_MAPPING: + logger.warning(f"Unknown emotion: {emotion}, using Neutral") + emotion = "Neutral" + + cluster_config = self.EMOTION_CLUSTER_MAPPING[emotion] + + # Build playlist + playlist = [] + for music_cluster in cluster_config: + logger.debug(f"Adding {music_cluster.count} songs from cluster {music_cluster.cluster_id} ({music_cluster.mood_category})") + + for _ in range(music_cluster.count): + _, formatted_song = self._select_song_from_cluster(music_cluster.cluster_id) + playlist.append(formatted_song) + + # Optional shuffle + if shuffle: + random.shuffle(playlist) + + logger.info(f"Generated playlist with {len(playlist)} songs") + return playlist + +def get_playlist(shuffle: bool = True) -> List[str]: + """ + Generate a music playlist based on current detected emotion. + + This function detects the user's emotion from a facial image and creates + a personalized playlist that matches their emotional state. Uses sophisticated + clustering algorithms to map emotions to music categories. + + Args: + shuffle: Whether to shuffle the playlist (default: True) + + Returns: + List of song filenames (format: "###.mp3_songname") + + Raises: + FileNotFoundError: If required files (image/database) don't exist + RuntimeError: If emotion detection or playlist generation fails + + Example: + >>> playlist = get_playlist() + >>> print(f"Generated {len(playlist)} songs") + Generated 21 songs + """ + try: + # Detect current emotion + current_emotion = get_emotion() + + # Generate playlist + generator = PlaylistGenerator() + playlist = generator.generate_playlist(current_emotion, shuffle=shuffle) + + return playlist + + except Exception as e: + logger.error(f"Playlist generation failed: {str(e)}") + raise RuntimeError(f"Failed to generate playlist: {str(e)}") def get_emotion_grid(): data = np.full((5,10), 81) From 3fdd73762619028368e164ecf97aceff026fbcb3 Mon Sep 17 00:00:00 2001 From: hot-path-bot Date: Wed, 22 Oct 2025 21:26:37 +0000 Subject: [PATCH 2/2] docs: AI-generated documentation updates Generated documentation for 10 functions using Hot-Path LLM. Files updated: - docs/API-Reference.md Generated with Hot-Path + LLM --- docs/API-Reference.md | 398 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) diff --git a/docs/API-Reference.md b/docs/API-Reference.md index e0921b4..c223df8 100644 --- a/docs/API-Reference.md +++ b/docs/API-Reference.md @@ -347,3 +347,401 @@ MUSIC_DIRECTORY = "static/music/" # Emotion graph output GRAPH_OUTPUT = "static/graph.jpg" ``` + + +## API Reference + + + + + + + + + + + +### clear_emotion_history + +*Source: `algorithmia.py`* + +{ + "updated_doc": "## clear_emotion_history + +Resets the global emotion history by clearing all stored emotions from memory. + +### Description +Clears the global `emot_list` by setting it to an empty list, effectively removing all previously stored emotion data. + +### Parameters +None + +### Returns +`int`: The length of the cleared emotion list (always returns 0) + +### Example Usage +```python +current_size = clear_emotion_history() # Returns 0 +``` + +### Notes +- This function modifies a global variable (`emot_list`) +- After calling this function, all previously stored emotion data will be permanently deleted +- This is typically used to reset the emotion tracking system to its initial state", + + "explanation": "This function provides a way to reset the emotion tracking system by clearing the global emotion history list. It's a simple but important utility function that helps manage memory and reset the system state. The function is straightforward - it replaces the global emot_list with an empty list and returns the new length (which will always be 0).", + + "confidence": 0.95 +} + +### get_emotion_count + +*Source: `algorithmia.py`* + +{ + "updated_doc": "## get_emotion_count() + +Returns the total number of emotions currently defined in the system. + +### Returns +- `int`: The count of emotions in the `emot_list` + +### Description +This utility function provides a simple way to get the total number of emotions available in the system by returning the length of the `emot_list` collection. + +### Example +```python +count = get_emotion_count() +print(f'Number of emotions available: {count}') +``` + +### Notes +- This is a read-only function that does not modify any state +- The return value depends on the current contents of `emot_list` +- Returns 0 if `emot_list` is empty", + "explanation": "This is a simple getter function that returns the length of a predefined emotion list. The function appears to be used for getting a count of available emotions in the system. While the implementation is straightforward, documenting the return type and purpose provides important context for API users. The function relies on an external `emot_list` variable which should be noted in the documentation.", + "confidence": 0.85 +} + +### _get_emotion_color_mapping + +*Source: `algorithmia.py`* + +{ + "updated_doc": "## _get_emotion_color_mapping + +Returns a dictionary mapping emotion labels to their corresponding color codes. + +### Returns +`Dict[str, int]`: A dictionary where: +- Keys are emotion labels (`str`): 'Neutral', 'Sad', 'Disgust', 'Fear', 'Surprise', 'Happy', 'Angry' +- Values are integer color codes (`int`): ranging from 1 to 61 + +### Details +The function provides a static mapping between seven basic emotions and their assigned color codes: +```python +{ + 'Neutral': 11, + 'Sad': 31, + 'Disgust': 51, + 'Fear': 61, + 'Surprise': 41, + 'Happy': 21, + 'Angry': 1 +} +``` + +### Notes +- This is an internal helper function (indicated by the leading underscore) +- The mapping is fixed and does not accept any parameters +- Color codes are non-sequential integers that correspond to specific emotion categories", + "explanation": "This is a new internal utility function that provides a static mapping between emotion labels and color codes. The function is straightforward - it simply returns a predefined dictionary. The color codes appear to be part of a broader emotion classification system, though their specific meaning would depend on how they're used in the larger application context.", + "confidence": 0.95 +} + +### _call_emotion_api + +*Source: `algorithmia.py`* + +{ + "updated_doc": "## _call_emotion_api + +Makes a call to the Algorithmia Emotion Recognition API to analyze emotions in an image. + +### Parameters + +- `image_path` (str, optional): Path to the image file to analyze. Defaults to 'snapshots/pic.png'. + +### Returns + +- `Dict`: Response dictionary from the emotion recognition API containing the analysis results. + +### Raises + +- `FileNotFoundError`: If the specified image file cannot be found at the given path +- `RuntimeError`: If the API call fails for any reason (connection issues, invalid API key, etc.) + +### Details + +The function performs the following steps: +1. Reads the image file as binary data +2. Initializes an Algorithmia client with an API key +3. Calls the EmotionRecognitionCNNMBP algorithm (version 1.0.1) +4. Returns the analysis results + +### Example Usage + +```python +try: + result = _call_emotion_api('path/to/image.jpg') + print(result) # Prints emotion analysis results +except RuntimeError as e: + print(f'Error analyzing image: {e}') +``` + +### Notes + +- Requires a valid Algorithmia API key to be configured +- The image file must be accessible and in a supported format +- All errors are logged before being re-raised", + "explanation": "This is a new function that provides a wrapper around the Algorithmia Emotion Recognition API. It handles the API authentication, file reading, and error management while providing a simple interface for emotion analysis of images. The documentation covers all major aspects including parameters, return values, error handling, and usage examples.", + "confidence": 0.9 +} + +### _load_song_database + +*Source: `algorithmia.py`* + +## _load_song_database + +### Description +Loads and caches song names from a pickle database file. If the songs are already loaded, returns the cached version. If not, attempts to load from the specified database file path. + +### Parameters +None + +### Returns +`Dict[int, str]`: A dictionary mapping song IDs (integers) to song names (strings) + +### Raises +- `FileNotFoundError`: If the song database file specified in `self.song_database_path` cannot be found + +### Implementation Details +- Uses pickle to deserialize the database file +- Database file is expected to be encoded in 'latin1' +- Results are cached in `self._song_names` for subsequent calls +- Logs the number of songs loaded using the logger at INFO level +- Logs errors at ERROR level if database file is not found + +### Example Usage +```python +song_names = instance._load_song_database() +# Returns: {1: 'Song Name 1', 2: 'Song Name 2', ...} +``` + +### Notes +- This is a protected method (indicated by the underscore prefix) +- The database path should be set in `self.song_database_path` before calling this method +- The method implements lazy loading - database is only read when first needed + +### _select_song_from_cluster + +*Source: `algorithmia.py`* + +## _select_song_from_cluster + +Selects and returns a random song from a specified music cluster. + +### Parameters + +- `cluster_id` (int): The identifier of the music cluster to select from. Must correspond to a valid cluster ID in `SONG_CLUSTERS`. + +### Returns + +`Tuple[int, str]`: A tuple containing: +- `song_id` (int): The numeric ID of the selected song +- `formatted_name` (str): The formatted song name in the pattern `"XXX.mp3_SongName"` where XXX is the zero-padded song ID + +### Description + +This internal method: +1. Loads the song database +2. Gets the valid song ID range for the specified cluster +3. Randomly selects a song ID within that range +4. Formats the song name according to the required pattern + +### Example + +```python +song_id, formatted_name = _select_song_from_cluster(1) +# Might return: (42, "042.mp3_Song Title") +``` + +### Notes + +- Requires `SONG_CLUSTERS` to be properly initialized with valid ranges +- Depends on `_load_song_database()` to provide song name mappings +- Uses zero-padding to ensure consistent 3-digit song IDs in formatted names + +### _parse_emotion_results + +*Source: `algorithmia.py`* + +## _parse_emotion_results + +Parses raw emotion detection API response data into a structured EmotionResult object. + +### Parameters +- `api_response` (Dict): Raw JSON response from the emotion detection API + +### Returns +- `EmotionResult`: Object containing: + - `emotion` (EmotionType): Dominant emotion detected + - `confidence` (float): Confidence score (0.0-1.0) for dominant emotion + - `all_emotions` (Dict[str, float]): All detected emotions and their confidence scores + - `color_code` (int): Color code associated with the dominant emotion + +### Behavior +1. If no results are found in the API response, defaults to 'Neutral' emotion with 100% confidence +2. Extracts emotion confidence scores from the first result +3. Determines dominant emotion based on highest confidence score +4. Maps emotion to corresponding color code +5. Maintains emotion history in global `emot_list` +6. Logs detection results at INFO level + +### Example Response Structure +```python +EmotionResult( + emotion=EmotionType.HAPPY, + confidence=0.85, + all_emotions={'Happy': 0.85, 'Neutral': 0.12, 'Sad': 0.03}, + color_code=5 +) +``` + +### Notes +- Internal function (prefixed with underscore) +- Falls back to Neutral emotion if parsing fails or invalid emotion detected +- Maintains global state through `emot_list` +- Requires `_get_emotion_color_mapping()` for color code lookup + +### __init__ + +*Source: `algorithmia.py`* + +## __init__ + +Initializes a new playlist generator instance. + +### Parameters + +- `song_database_path` (str, optional): Path to the pickled song database file + - Default value: "test.txt" + +### Attributes + +- `song_database_path`: Stores the provided database file path +- `_song_names`: Internal cache for song names (initialized as None) + +### Example + +```python +# Initialize with default database path +playlist_gen = PlaylistGenerator() + +# Initialize with custom database path +playlist_gen = PlaylistGenerator(song_database_path="songs.pkl") +``` + +### Notes + +- The song database file should exist and be properly formatted +- The `_song_names` attribute is meant for internal use as indicated by the underscore prefix + +### generate_playlist + +*Source: `algorithmia.py`* + +## generate_playlist(emotion: str, shuffle: bool = True) -> List[str] + +Generates a playlist of songs based on a detected emotional state. + +### Parameters + +- `emotion` (str): The detected emotion to generate a playlist for. If the emotion is not recognized, defaults to "Neutral". +- `shuffle` (bool, optional): Whether to randomize the order of songs in the final playlist. Defaults to True. + +### Returns + +- List[str]: A list of song filenames that make up the generated playlist + +### Description + +This function creates a customized playlist by: +1. Looking up the cluster configuration associated with the given emotion +2. Selecting the specified number of songs from each music cluster +3. Optionally shuffling the final playlist + +### Example Usage + +```python +playlist = music_system.generate_playlist("Happy", shuffle=True) +# Returns: ["song1.mp3", "song2.mp3", ...] +``` + +### Notes + +- If an unrecognized emotion is provided, the function will fall back to using the "Neutral" emotion configuration and log a warning +- The number and type of songs selected is determined by the EMOTION_CLUSTER_MAPPING configuration +- Songs are selected from predefined clusters associated with different mood categories + +### Logging + +The function logs: +- INFO level when starting playlist generation and completing it +- DEBUG level when adding songs from specific clusters +- WARNING level when handling unknown emotions + +### get_emotion_detailed + +*Source: `algorithmia.py`* + +{ + "updated_doc": "## get_emotion_detailed + +Analyzes an image file to detect and quantify emotions, providing detailed confidence scores for each detected emotion. + +### Parameters + +- `image_path` (str, optional): + - Path to the image file to analyze + - Default value: `'snapshots/pic.png'` + +### Returns + +- `EmotionResult`: + - Object containing detailed emotion detection results + - Includes confidence scores for all detected emotions + +### Example Usage + +```python +result = get_emotion_detailed('path/to/image.jpg') +# Returns EmotionResult object with detailed emotion data +``` + +### Implementation Details + +The function works in two steps: +1. Calls the emotion detection API using the provided image +2. Parses and structures the API response into an EmotionResult object + +### Notes + +- Ensure the image file exists at the specified path +- The image should contain clearly visible faces for best results +- Processing time may vary based on image size and complexity", + "explanation": "This is a new function that provides a wrapper around emotion detection API calls. It simplifies the process of getting detailed emotion analysis results from images by handling both the API call and response parsing in a single function call. The function is designed to provide more comprehensive emotion detection data compared to simpler emotion detection methods.", + "confidence": 0.85 +} +