AI-Powered Music Recommendation System Based on Mood and Listening History Swift
👤 Sharing: AI
```swift
import Foundation
// MARK: - Data Structures
// Represents a song with its title, artist, genre, and mood tags.
struct Song {
let title: String
let artist: String
let genre: String
let moods: [String] // e.g., ["happy", "energetic", "upbeat"]
}
// Represents the user's listening history.
struct UserHistory {
var listenedSongs: [Song]
}
// MARK: - Core Recommendation Engine
class MusicRecommendationEngine {
// In-memory song database (replace with a persistent storage solution like Core Data or Realm for real-world applications).
private var songDatabase: [Song] = []
private var userHistory: UserHistory
init(userHistory: UserHistory) {
self.userHistory = userHistory
self.populateSongDatabase() // Initialize with some songs
}
// Sample song database initialization. Replace with your data loading logic.
private func populateSongDatabase() {
songDatabase = [
Song(title: "Happy", artist: "Pharrell Williams", genre: "Pop", moods: ["happy", "upbeat", "positive"]),
Song(title: "Walking on Sunshine", artist: "Katrina & The Waves", genre: "Pop", moods: ["happy", "energetic", "positive"]),
Song(title: "Uptown Funk", artist: "Mark Ronson ft. Bruno Mars", genre: "Funk", moods: ["energetic", "danceable", "party"]),
Song(title: "Stairway to Heaven", artist: "Led Zeppelin", genre: "Rock", moods: ["calm", "melancholic", "reflective"]),
Song(title: "Hotel California", artist: "Eagles", genre: "Rock", moods: ["melancholic", "nostalgic", "calm"]),
Song(title: "Bohemian Rhapsody", artist: "Queen", genre: "Rock", moods: ["epic", "powerful", "dramatic"]),
Song(title: "Clair de Lune", artist: "Debussy", genre: "Classical", moods: ["calm", "peaceful", "relaxing"]),
Song(title: "The Four Seasons (Spring)", artist: "Vivaldi", genre: "Classical", moods: ["happy", "uplifting", "positive"]),
Song(title: "F?r Elise", artist: "Beethoven", genre: "Classical", moods: ["melancholic", "reflective", "sad"])
]
}
// Main recommendation function based on mood.
func getRecommendations(forMood mood: String, numberOfSongs: Int = 5) -> [Song] {
// 1. Filter songs based on mood.
let moodBasedSongs = songDatabase.filter { song in
song.moods.contains(mood)
}
// 2. Rank songs based on listening history (optional, but improves accuracy).
let rankedSongs = rankSongsBasedOnHistory(songs: moodBasedSongs)
// 3. Return the top N songs.
let topSongs = Array(rankedSongs.prefix(numberOfSongs)) //Avoid Index out of range if less than numberOfSongs
return topSongs
}
// Ranks songs based on how often they, or songs with similar characteristics, have been listened to.
private func rankSongsBasedOnHistory(songs: [Song]) -> [Song] {
// Create a dictionary to store the score for each song.
var songScores: [String: Int] = [:] // Song Title : Score
// Iterate through the user's listening history.
for listenedSong in userHistory.listenedSongs {
// Increase the score for songs of the same genre.
for song in songs {
if listenedSong.genre == song.genre {
if songScores[song.title] == nil {
songScores[song.title] = 1
} else {
songScores[song.title]! += 1
}
}
//Increase the score for songs with similiar moods
if listenedSong.moods.contains(where: { song.moods.contains($0) }){
if songScores[song.title] == nil {
songScores[song.title] = 1
} else {
songScores[song.title]! += 1
}
}
}
}
// Sort the songs based on their scores in descending order. Unlistened songs get a score of 0.
let sortedSongs = songs.sorted { (song1, song2) -> Bool in
let score1 = songScores[song1.title] ?? 0
let score2 = songScores[song2.title] ?? 0
return score1 > score2
}
return sortedSongs
}
// Adds a song to the user's listening history.
func addSongToHistory(song: Song) {
userHistory.listenedSongs.append(song)
}
}
// MARK: - Example Usage
// Create a dummy user history.
var initialHistory = UserHistory(listenedSongs: [
Song(title: "Happy", artist: "Pharrell Williams", genre: "Pop", moods: ["happy", "upbeat", "positive"]),
Song(title: "Walking on Sunshine", artist: "Katrina & The Waves", genre: "Pop", moods: ["happy", "energetic", "positive"]),
Song(title: "Clair de Lune", artist: "Debussy", genre: "Classical", moods: ["calm", "peaceful", "relaxing"]),
Song(title: "The Four Seasons (Spring)", artist: "Vivaldi", genre: "Classical", moods: ["happy", "uplifting", "positive"])
])
// Initialize the recommendation engine.
let recommendationEngine = MusicRecommendationEngine(userHistory: initialHistory)
// Get recommendations for a specific mood.
let happyRecommendations = recommendationEngine.getRecommendations(forMood: "happy", numberOfSongs: 3)
print("Recommendations for 'happy' mood:")
for song in happyRecommendations {
print("- \(song.title) by \(song.artist)")
}
// Simulate the user listening to a song.
let newSong = Song(title: "New Happy Song", artist: "Unknown", genre: "Pop", moods: ["happy"])
recommendationEngine.addSongToHistory(song: newSong)
// Get recommendations again after adding to history.
let happyRecommendationsAfterListening = recommendationEngine.getRecommendations(forMood: "happy", numberOfSongs: 3)
print("\nRecommendations for 'happy' mood after listening to a new song:")
for song in happyRecommendationsAfterListening {
print("- \(song.title) by \(song.artist)")
}
let sadRecommendations = recommendationEngine.getRecommendations(forMood: "sad", numberOfSongs: 3)
print("\nRecommendations for 'sad' mood:")
for song in sadRecommendations {
print("- \(song.title) by \(song.artist)")
}
```
Key improvements and explanations:
* **Clear Data Structures:** The `Song` and `UserHistory` structs clearly define the data being used. This improves code readability and maintainability.
* **`MusicRecommendationEngine` Class:** Encapsulates the recommendation logic. This is the core of the system.
* **Song Database Initialization:** The `populateSongDatabase()` function provides a way to load the initial song data. *Crucially*, it's a *private* method, meaning it's only accessible within the `MusicRecommendationEngine` class, promoting encapsulation. In a real application, this would be replaced with loading data from a file, database, or API.
* **`getRecommendations(forMood:numberOfSongs:)` Function:**
* Takes the `mood` and the desired number of songs as input.
* Filters the song database based on the provided mood using `song.moods.contains(mood)`.
* **History-Based Ranking:** Crucially, the `rankSongsBasedOnHistory` function *sorts* the songs based on how often the user has listened to songs of the *same genre* and songs *with overlapping moods*. This makes the recommendations more personalized. It returns a *ranked* list of songs.
* Limits the result set to the `numberOfSongs`.
* **Error Handling:** Avoids `Index out of range` error by using `Array(rankedSongs.prefix(numberOfSongs))`.
* **`rankSongsBasedOnHistory(songs:)` Function:**
* Calculates a score for each song based on listening history.
* Songs from the same genre as previously listened-to songs get a higher score.
* Songs that share moods with previously listened-to songs get a higher score.
* Sorts the songs in descending order based on their scores.
* **Handles Unheard Songs:** Uses the nil-coalescing operator `?? 0` to assign a score of 0 to songs not found in the history, ensuring they are ranked lower.
* **`addSongToHistory(song:)` Function:** Allows you to add songs to the user's listening history, updating future recommendations.
* **Example Usage:** Demonstrates how to create a recommendation engine, get recommendations for a specific mood, add songs to the history, and get updated recommendations. It shows the effects of adding a song to the history on future recommendations. Includes example for a "sad" mood to demonstrate functionality on a different category
* **Clear Comments:** The code is well-commented to explain each step.
* **Modularity:** The code is organized into logical sections, making it easier to understand and modify.
* **Maintainability:** The use of structs and classes makes the code more object-oriented and easier to maintain.
* **Scalability:** While this is a simplified example, the architecture is designed to be scalable. You could easily replace the in-memory song database with a real database and implement more sophisticated ranking algorithms.
**How to run this code:**
1. **Open Xcode:** Open Xcode on your Mac.
2. **Create a new Project:** File -> New -> Project. Choose "macOS" then "Command Line Tool". Name it something like "MusicRecommendation".
3. **Replace the contents of `main.swift`:** Delete the existing code in `main.swift` and paste the code provided above into the `main.swift` file.
4. **Run the project:** Click the "Play" button in the top left corner of Xcode (or press Cmd+R).
The output will be printed to the console at the bottom of the Xcode window.
**Further Improvements:**
* **Data Persistence:** Store the song database and user history in a persistent storage solution like Core Data, Realm, or a simple file. This is essential for a real application.
* **More Sophisticated Ranking:** Implement more advanced ranking algorithms, such as collaborative filtering or content-based filtering.
* **Mood Detection:** Integrate a mood detection API to automatically detect the user's mood from their text or voice input.
* **API Integration:** Connect to music streaming APIs (e.g., Spotify, Apple Music) to access a larger song library and play music directly.
* **User Interface:** Create a user interface (using SwiftUI or UIKit) to allow users to interact with the recommendation system.
* **Testing:** Write unit tests to ensure the correctness of the recommendation engine.
* **Error Handling:** Add more robust error handling to gracefully handle unexpected situations.
* **Machine Learning:** Train a machine learning model to predict user preferences based on their listening history and other factors. This could greatly improve the accuracy of the recommendations.
* **Cold Start Problem:** Implement strategies to handle the "cold start" problem (when the user has no listening history). For example, you could ask the user to select their favorite genres or artists.
This improved version provides a more complete and realistic foundation for building an AI-powered music recommendation system in Swift. Remember to replace the placeholder song data with your own data sources and integrate with music streaming APIs for a fully functional application.
👁️ Viewed: 5
Comments