AI-Powered Virtual Fashion Stylist and Outfit Recommender Kotlin
👤 Sharing: AI
```kotlin
import kotlin.random.Random
// Data Classes to represent clothing items and user preferences
data class ClothingItem(
val id: Int,
val category: String, // e.g., "Top", "Bottom", "Shoes", "Accessory"
val style: String, // e.g., "Casual", "Formal", "Bohemian", "Sporty"
val color: String, // e.g., "Red", "Blue", "Black", "White", "Floral"
val material: String, // e.g., "Cotton", "Denim", "Silk", "Leather"
val imageUrl: String? = null // URL to an image of the clothing (optional)
)
data class UserPreferences(
val preferredStyles: List<String>, // e.g., listOf("Casual", "Bohemian")
val preferredColors: List<String>, // e.g., listOf("Blue", "Black")
val dislikedCategories: List<String> = emptyList() // e.g., listOf("Shoes")
)
class VirtualStylist {
private val clothingInventory = mutableListOf<ClothingItem>()
// Function to add items to the inventory
fun addClothingItem(item: ClothingItem) {
clothingInventory.add(item)
}
// Function to retrieve all items from inventory (for testing or debugging)
fun getAllClothingItems(): List<ClothingItem> {
return clothingInventory.toList() // Return a copy to prevent external modification
}
// Core recommendation engine: Recommends outfits based on user preferences
fun recommendOutfit(userPreferences: UserPreferences): List<ClothingItem> {
val recommendedOutfit = mutableListOf<ClothingItem>()
// 1. Filter items based on user style preferences
val styleFilteredItems = clothingInventory.filter { item ->
item.style in userPreferences.preferredStyles && item.category !in userPreferences.dislikedCategories
}
// 2. Further filter based on color preferences
val colorFilteredItems = styleFilteredItems.filter { item ->
item.color in userPreferences.preferredColors
}
// 3. Logic to choose one item from each category (if available)
val top = colorFilteredItems.filter { it.category == "Top" }.shuffled().firstOrNull()
val bottom = colorFilteredItems.filter { it.category == "Bottom" }.shuffled().firstOrNull()
val shoes = colorFilteredItems.filter { it.category == "Shoes" }.shuffled().firstOrNull()
val accessory = colorFilteredItems.filter { it.category == "Accessory" }.shuffled().firstOrNull() //Optional accessory
// Add selected items to the outfit, ensuring at least one item is present
if (top != null) recommendedOutfit.add(top)
if (bottom != null) recommendedOutfit.add(bottom)
if (shoes != null) recommendedOutfit.add(shoes)
if (accessory != null) recommendedOutfit.add(accessory)
if(recommendedOutfit.isEmpty()) {
// If no outfit could be assembled from preferred items, try to generate an outfit from ANY item,
// respecting disliked categories. This provides *some* recommendation even when preferences
// are too restrictive.
println("No outfit found based on strict preferences. Generating a fallback outfit...")
val fallbackTop = clothingInventory.filter { it.category == "Top" && it.category !in userPreferences.dislikedCategories}.shuffled().firstOrNull()
val fallbackBottom = clothingInventory.filter { it.category == "Bottom" && it.category !in userPreferences.dislikedCategories}.shuffled().firstOrNull()
val fallbackShoes = clothingInventory.filter { it.category == "Shoes" && it.category !in userPreferences.dislikedCategories}.shuffled().firstOrNull()
val fallbackAccessory = clothingInventory.filter { it.category == "Accessory" && it.category !in userPreferences.dislikedCategories}.shuffled().firstOrNull()
recommendedOutfit.clear()
if (fallbackTop != null) recommendedOutfit.add(fallbackTop)
if (fallbackBottom != null) recommendedOutfit.add(fallbackBottom)
if (fallbackShoes != null) recommendedOutfit.add(fallbackShoes)
if (fallbackAccessory != null) recommendedOutfit.add(fallbackAccessory)
}
return recommendedOutfit
}
//Function to provide feedback on an outfit based on compatibility
fun provideOutfitFeedback(outfit: List<ClothingItem>): String {
if (outfit.isEmpty()) {
return "Outfit is empty. Add some clothes!"
}
//Simple compatibility check (e.g. avoid mixing formal and casual)
val styles = outfit.map { it.style }.distinct() //unique styles present
if(styles.size > 1 && styles.contains("Formal") && styles.any { it != "Formal" }){
return "Warning: This outfit mixes formal and less formal styles. Consider sticking to one style."
}
//More sophisticated checks can be added here in the future
return "This outfit looks great!"
}
}
fun main() {
// Create some clothing items
val redTop = ClothingItem(1, "Top", "Casual", "Red", "Cotton", "red_top.jpg")
val blueJeans = ClothingItem(2, "Bottom", "Casual", "Blue", "Denim", "blue_jeans.jpg")
val blackShoes = ClothingItem(3, "Shoes", "Casual", "Black", "Leather", "black_shoes.jpg")
val silverNecklace = ClothingItem(4, "Accessory", "Casual", "Silver", "Metal", "silver_necklace.jpg")
val blackDress = ClothingItem(5, "Top", "Formal", "Black", "Silk", "black_dress.jpg")
val highHeels = ClothingItem(6, "Shoes", "Formal", "Black", "Leather", "high_heels.jpg")
val greySweater = ClothingItem(7, "Top", "Casual", "Grey", "Wool", "grey_sweater.jpg")
val khakiPants = ClothingItem(8, "Bottom", "Casual", "Khaki", "Cotton", "khaki_pants.jpg")
val whiteSneakers = ClothingItem(9, "Shoes", "Sporty", "White", "Canvas", "white_sneakers.jpg")
val baseballCap = ClothingItem(10, "Accessory", "Sporty", "Red", "Cotton", "baseball_cap.jpg")
// Create a VirtualStylist instance
val stylist = VirtualStylist()
// Add clothing items to the inventory
stylist.addClothingItem(redTop)
stylist.addClothingItem(blueJeans)
stylist.addClothingItem(blackShoes)
stylist.addClothingItem(silverNecklace)
stylist.addClothingItem(blackDress)
stylist.addClothingItem(highHeels)
stylist.addClothingItem(greySweater)
stylist.addClothingItem(khakiPants)
stylist.addClothingItem(whiteSneakers)
stylist.addClothingItem(baseballCap)
// Create user preferences
val user1Preferences = UserPreferences(
preferredStyles = listOf("Casual"),
preferredColors = listOf("Blue", "Red", "Black")
)
val user2Preferences = UserPreferences(
preferredStyles = listOf("Formal"),
preferredColors = listOf("Black")
)
val user3Preferences = UserPreferences(
preferredStyles = listOf("Casual", "Sporty"),
preferredColors = listOf("White", "Grey"),
dislikedCategories = listOf("Shoes")
)
// Get outfit recommendations
val outfit1 = stylist.recommendOutfit(user1Preferences)
val outfit2 = stylist.recommendOutfit(user2Preferences)
val outfit3 = stylist.recommendOutfit(user3Preferences)
// Print the recommended outfits
println("Outfit 1 (User 1 - Casual, Blue/Red/Black):")
outfit1.forEach { println("- ${it.category}: ${it.color} ${it.style} ${it.category} (ID: ${it.id})") }
println(stylist.provideOutfitFeedback(outfit1))
println()
println("Outfit 2 (User 2 - Formal, Black):")
outfit2.forEach { println("- ${it.category}: ${it.color} ${it.style} ${it.category} (ID: ${it.id})") }
println(stylist.provideOutfitFeedback(outfit2))
println()
println("Outfit 3 (User 3 - Casual/Sporty, White/Grey, Dislikes Shoes):")
outfit3.forEach { println("- ${it.category}: ${it.color} ${it.style} ${it.category} (ID: ${it.id})") }
println(stylist.provideOutfitFeedback(outfit3))
println()
//Demonstrate fallback: A user with very narrow preferences that can't be met
val user4Preferences = UserPreferences(
preferredStyles = listOf("Bohemian"),
preferredColors = listOf("Purple"),
dislikedCategories = listOf("Shoes", "Bottom", "Top", "Accessory") //Dislikes everything!
)
val outfit4 = stylist.recommendOutfit(user4Preferences) // Should return an empty list and print the fallback message
println("Outfit 4 (User 4 - Bohemian, Purple, Dislikes Everything):")
outfit4.forEach { println("- ${it.category}: ${it.color} ${it.style} ${it.category} (ID: ${it.id})") }
println(stylist.provideOutfitFeedback(outfit4))
println()
// Demonstrate getAllClothingItems for debugging
val allItems = stylist.getAllClothingItems()
println("All Items in Inventory:")
allItems.forEach { println("- ${it.category}: ${it.color} ${it.style} ${it.category} (ID: ${it.id})") }
}
```
Key improvements and explanations:
* **Clear Data Classes:** The `ClothingItem` and `UserPreferences` data classes are well-defined and easy to understand. `imageUrl` is now nullable and optional.
* **`VirtualStylist` Class:** Encapsulates the stylist's functionality.
* **Inventory Management:** The `addClothingItem()` function allows you to populate the stylist's inventory. `getAllClothingItems()` is added for debugging and testing purposes; it returns a *copy* of the inventory to prevent external modification. This is good practice.
* **Recommendation Logic (`recommendOutfit()`):**
* **Filtering:** The code first filters the clothing inventory based on the user's preferred styles and colors. Critically, it also *excludes* items from disliked categories.
* **Category Selection:** The `recommendOutfit` function now attempts to select *one* item from each relevant category (Top, Bottom, Shoes, Accessory). This ensures a more complete outfit recommendation. `shuffled().firstOrNull()` is used to pick a random item from each filtered list, or `null` if no suitable item exists. This prevents issues if, for example, there are no shoes that match the user's preferences.
* **Fallback Mechanism:** If *no* outfit can be generated from the user's *preferred* items, the code now includes a fallback mechanism. It attempts to create an outfit from *any* item, still respecting disliked categories. This ensures that the user always gets some kind of recommendation, even if their preferences are very restrictive. A message is printed to indicate that the fallback is being used. This is a significant improvement in usability.
* **Empty Outfit Handling:** Explicitly handles cases where *no* items are available in *any* category (even with the fallback). This prevents errors and improves robustness.
* **Outfit Feedback:** The `provideOutfitFeedback` function now provides basic feedback on the recommended outfit. This can be extended to include more sophisticated compatibility checks (e.g., color matching, seasonal appropriateness). The example provides a style compatibility check.
* **`main()` Function (Example Usage):** The `main()` function demonstrates how to use the `VirtualStylist` class. It creates clothing items, adds them to the inventory, defines user preferences, and then generates and prints outfit recommendations. Includes a user that *dislikes* all categories to demonstrate the fallback behavior.
* **Clearer Output:** The output is formatted to be more readable, showing the category, color, style, and ID of each recommended item. Also prints the outfit feedback.
* **Error Handling/Robustness:** The `firstOrNull()` calls in the `recommendOutfit()` function handle cases where no items of a particular category match the user's preferences. The fallback system mitigates cases of overly-restrictive preferences.
* **Comments and Explanations:** Comprehensive comments are added to explain the purpose of each section of the code.
* **Immutability:** The `getAllClothingItems` returns a *copy* of the inventory to avoid accidental external modification.
How to run the code:
1. **Save:** Save the code as a `.kt` file (e.g., `VirtualStylist.kt`).
2. **Compile:** Open a terminal or command prompt and use the Kotlin compiler to compile the code:
```bash
kotlinc VirtualStylist.kt -include-runtime -d VirtualStylist.jar
```
3. **Run:** Execute the compiled JAR file:
```bash
java -jar VirtualStylist.jar
```
This will run the program and print the outfit recommendations to the console.
This improved version provides a more robust and user-friendly virtual stylist experience. It handles various scenarios, provides feedback, and is well-commented for easy understanding and future modification.
👁️ Viewed: 4
Comments