{"slug": "dresscode-your-ai-stylist-for-tomorrow", "title": "DressCode: Your AI Stylist for Tomorrow", "summary": "DressCode is an AI-powered styling app built with Google's Gemma 4 that helps users choose weather-appropriate outfits by analyzing uploaded photos of their clothes. The app uses Gemma 4's image understanding to extract details like color, category, and seasonality from each clothing item, then combines this with weather forecast data to suggest complete, coordinated outfits. The system relies on structured JSON output via Pydantic schemas to organize clothing data efficiently, enabling intelligent wardrobe management without manual input.", "body_md": "*This is a submission for the Gemma 4 Challenge: Write About Gemma 4*\n\nGetting dressed is often stressful. What should you wear when the weather keeps changing?\n\nDressCode makes it simple. Powered by Google’s Gemma 4 AI, this app helps you choose the right clothes for the weather tomorrow.\n\nJust upload photos of your clothes. The AI will describe each item, recognize the colors, and know if it’s for cold, warm, spring, or winter weather.\n\nTell the app the date and time of your event. It checks the weather forecast and suggests complete outfits that match in style and color.\n\nDressCode saves you time and helps you look good every day.\n\nSmart. Simple. Always dressed right.\n\nTo build DressCode, we rely on two main capabilities from Google’s Gemma 4 AI:\n\nIf in a hurry, look for the core code [here](https://github.com/saad4software/dresscode-core)\n\nand the backend code [here](https://github.com/saad4software/dresscode-back)\n\n### 1. Smart Clothing Analysis\n\nWhen users upload photos of their clothes, Gemma 4 analyzes the images and extracts as many details as possible to sort outfits, details like:\n\n- Identifies each piece of clothing (shirt, pants, jacket, dress, etc.)\n- Describes important details: color, pattern, style, material, and type\n- Determines weather suitability (warm, cold, spring, winter, etc.)\n\nThis allows the app to understand the user’s wardrobe without manual input.\n\n### 2. Weather-Based Outfit Generation\n\nGemma 4 then uses the second key function:\n\n- Checks the weather forecast for the selected date and time (day or night)\n- Understands the season and weather conditions\n- Picks the best matching clothes from the user’s collection\n- Creates complete, well-coordinated outfits that match in color and style\n\nBy combining powerful image understanding with smart reasoning, Gemma 4 turns your personal closet into an intelligent, weather-aware stylist.\n\nThis is the core technology behind DressCode — making outfit decisions fast, easy, and always appropriate for the weather.\n\n## Setup AI Studio project\n\nIn order to use Gemma, we need an API key. and in order to get the key, we need to create a [project](https://aistudio.google.com/projects)\n\nand after creating and naming the project, we can get the api key from the project.\n\n## Setup the environment\n\nUsing `UV`\n\nfor the virtual environment, we only need the project file and sync the requirements\n\nproject.toml\n\n```\n[project]\nname = \"dresscode\"\nversion = \"0.1.0\"\ndescription = \"Add your description here\"\nreadme = \"README.md\"\nrequires-python = \">=3.12\"\ndependencies = [\n    \"google>=3.0.0\",\n    \"google-genai>=2.4.0\",\n    \"python-dotenv>=1.2.2\",\n    \"requests>=2.34.2\",\n]\nuv sync\n```\n\n## Smart Clothing Analysis\n\nOne of the most important features in DressCode is Smart Clothing Analysis. When a user uploads a photo of their clothes, the app needs to understand every item clearly and return the information in a clean, organized way.\n\nTo achieve this, we use Gemma 4 with a structured prompt and JSON schema. Here’s how it works:\n\nGemma 4 analyzes the image and identifies every distinct clothing item and accessory. It then returns the results as a well-organized JSON object.\n\nThe model extracts key details for each item, including:\n\n- Item name\n- Category (top, bottom, dress, shoes, etc.)\n- Colors (as hex codes)\n- Dominant color\n- Warmth level\n- Season suitability\n- Style, material, pattern, formality, and more\n\nBy using response_mime_type=\"application/json\" and a strict Pydantic schema, we force Gemma 4 to return clean, consistent, and ready-to-use data. This makes it easy for the app to save each clothing item into the database without extra processing.\n\nThis organized JSON output is the foundation of DressCode’s intelligent wardrobe system. It allows the AI to truly understand the user’s clothes before suggesting perfect outfits.\n\nWe need to set up the `GEMINI_API_KEY`\n\nas an environment variable. Let's create a `.env`\n\nfile and set it.\n\n```\nGEMINI_API_KEY=AIz...\n```\n\nNow for the clothes analysis script\n\n``` python\nfrom google import genai\nfrom dotenv import load_dotenv\nfrom google.genai import types\nfrom pydantic import BaseModel, Field\nfrom typing import List\n\nload_dotenv()\n\n# 1. Define the structure for a single clothing piece\nclass ClothingItem(BaseModel):\n    name: str = Field(description=\"Name or short description of the piece\")\n    category: str = Field(description=\"Must be one of: Top, Bottom, Outerwear, Footwear\")\n    color_palette: str = Field(description=\"Dominant colors, e.g., Navy Blue, Warm Beige\")\n    seasonality: str = Field(description=\"e.g., Heavy Winter, Light Spring, Hot Summer\")\n    style_vibe: str = Field(description=\"e.g., Formal, Casual, Streetwear, Athletic\")\n    location_in_image: str = Field(description=\"where it is relative to the scene, e.g. [200, 123, 1000, 1000]'\")\n\n# 2. Define the container for the final list\nclass ClosetAnalysis(BaseModel):\n    clothes: List[ClothingItem]\n\nclient = genai.Client()\n\nimage_path = \"strikkeopskrift-p.jpg\" \n\nwith open(image_path, \"rb\") as f:\n    image_bytes = f.read()\n\nresponse = client.models.generate_content(\n    model=\"gemma-4-26b-a4b-it\",\n    contents=[\n        types.Part.from_bytes(\n            data=image_bytes,\n            mime_type=\"image/jpeg\",\n        ), \n        \"Analyze the clothing pieces visible in this image and catalog them strictly according to the schema.\",\n        ],\n        config=types.GenerateContentConfig(\n            response_mime_type=\"application/json\",\n            response_schema=ClosetAnalysis,\n        ),\n)\n\nprint(response.text)\n```\n\nThis script will generate a response following the schema provided, but for more details, I would update the analysis prompt to\n\n```\nDRESS_VISION_PROMPT = (\n    \"Analyze every distinct clothing item visible in this image and catalog \"\n    \"each one as a separate entry in the `items` array, strictly according \"\n    \"to the schema. Include ALL visible garments and wearable items: tops, \"\n    \"bottoms, outerwear, dresses, shoes, socks, hats, bags, and accessories. \"\n    \"Do not skip smaller or partial items—if shoes, socks, a hat, jewelry, \"\n    \"a belt, scarf, tie, watch, or sunglasses are visible, each gets its own \"\n    \"entry with the correct category: \"\n    \"shoes for any footwear; socks for socks or visible hosiery; hat for \"\n    \"hats, caps, and beanies; accessory for jewelry, belts, scarves, ties, \"\n    \"watches, sunglasses, gloves, and similar add-ons; bag for handbags and \"\n    \"backpacks. \"\n    \"Do not merge multiple garments into one entry. \"\n    \"If only one garment is visible, return a single-item array. \"\n    \"Colors must be lowercase 7-character hex strings starting with '#'.\"\n)\n```\n\nAnd I would update the JSON response to allow multiple pieces of clothing.\n\nschemas.py\n\n``` python\nfrom datetime import datetime, timezone\nfrom typing import Optional\nfrom enum import Enum\n\nfrom pydantic import BaseModel, Field, field_validator\n\nclass Category(str, Enum):\n    top = \"top\"\n    bottom = \"bottom\"\n    outerwear = \"outerwear\"\n    shoes = \"shoes\"\n    accessory = \"accessory\"\n    dress = \"dress\"\n    underwear = \"underwear\"\n    bag = \"bag\"\n    hat = \"hat\"\n    socks = \"socks\"\n    other = \"other\"\n\nclass WarmthLevel(str, Enum):\n    light = \"light\"\n    medium = \"medium\"\n    heavy = \"heavy\"\n\nclass Season(str, Enum):\n    summer = \"summer\"\n    winter = \"winter\"\n    spring = \"spring\"\n    fall = \"fall\"\n    all_season = \"all_season\"\n\nclass Layering(str, Enum):\n    base = \"base\"\n    mid = \"mid\"\n    outer = \"outer\"\n\nclass Pattern(str, Enum):\n    solid = \"solid\"\n    striped = \"striped\"\n    plaid = \"plaid\"\n    floral = \"floral\"\n    graphic = \"graphic\"\n    other = \"other\"\n\nclass Formality(str, Enum):\n    casual = \"casual\"\n    smart_casual = \"smart_casual\"\n    business = \"business\"\n    formal = \"formal\"\n\nclass Brightness(str, Enum):\n    light = \"light\"\n    dark = \"dark\"\n    mixed = \"mixed\"\n\nclass DressStatus(str, Enum):\n    draft = \"draft\"\n    ready = \"ready\"\n    needs_review = \"needs_review\"\n\nclass DressVisionMultiResult(BaseModel):\n    \"\"\"JSON schema sent to Gemma when cataloging all garments in one image.\"\"\"\n\n    items: list[\"DressVisionResult\"] = Field(\n        min_length=1,\n        description=(\n            \"One entry per distinct garment or wearable visible in the image \"\n            \"(e.g. top, bottom, shoes, socks, hat, accessory in an outfit photo)\"\n        ),\n    )\n\nclass DressVisionResult(BaseModel):\n    \"\"\"Vision metadata for a single clothing item.\"\"\"\n\n    item_name: str = Field(description=\"Short human-readable name of the garment\")\n    category: Category = Field(\n        description=\"One of: top, bottom, outerwear, shoes, socks, accessory, \"\n        \"dress, underwear, bag, hat, other\"\n    )\n    colors: list[str] = Field(\n        default_factory=list,\n        description=\"All visible colors as #rrggbb hex strings\",\n    )\n    dominant_color: str = Field(description=\"Primary color as #rrggbb\")\n    warmth_level: WarmthLevel = Field(\n        description=\"One of: light, medium, heavy\"\n    )\n    season_suitability: list[Season] = Field(\n        default_factory=list,\n        description=\"One or more of: summer, winter, spring, fall, all_season\",\n    )\n    style: list[str] = Field(\n        default_factory=list,\n        description=\"Short style tags, e.g. casual, formal, streetwear\",\n    )\n    description: str = Field(\n        description=\"Concise visual description (1-3 sentences)\"\n    )\n    layering: Layering = Field(description=\"One of: base, mid, outer\")\n    pattern: Optional[Pattern] = Field(\n        default=None,\n        description=\"One of: solid, striped, plaid, floral, graphic, other\",\n    )\n    material: Optional[str] = Field(\n        default=None, description=\"Best guess of fabric, e.g. cotton, wool, denim\"\n    )\n    formality: Optional[Formality] = Field(\n        default=None,\n        description=\"One of: casual, smart_casual, business, formal\",\n    )\n    brightness: Optional[Brightness] = Field(\n        default=None, description=\"One of: light, dark, mixed\"\n    )\n    water_resistant: bool = Field(default=False)\n    occasion_tags: list[str] = Field(\n        default_factory=list,\n        description=\"Short occasion tags, e.g. work, party, outdoor, gym\",\n    )\n    confidence: Optional[float] = Field(\n        default=None, ge=0.0, le=1.0, description=\"Model confidence from 0 to 1\"\n    )\n\nclass DressCatalogItem(BaseModel):\n    \"\"\"Slim wardrobe item shape sent to Gemma for outfit selection.\"\"\"\n\n    id: int\n    item_name: Optional[str] = None\n    category: Optional[Category] = None\n    colors: list[str] = Field(default_factory=list)\n    dominant_color: Optional[str] = None\n    warmth_level: Optional[WarmthLevel] = None\n    season_suitability: list[Season] = Field(default_factory=list)\n    style: list[str] = Field(default_factory=list)\n    formality: Optional[Formality] = None\n    brightness: Optional[Brightness] = None\n    layering: Optional[Layering] = None\n    pattern: Optional[Pattern] = None\n    material: Optional[str] = None\n    water_resistant: bool = False\n    occasion_tags: list[str] = Field(default_factory=list)\n    description: Optional[str] = None\n```\n\nso the new process images script will look more like\n\nmain.py\n\n``` python\nfrom google import genai\nfrom dotenv import load_dotenv\nfrom google.genai import types\nfrom pydantic import BaseModel, Field\nfrom typing import List\nfrom enum import Enum\nfrom schemas import DressVisionMultiResult\nfrom scripts import DRESS_VISION_PROMPT\n\nload_dotenv()\n\nclient = genai.Client()\n\nimage_path = \"outfit.jpg\" \n\nwith open(image_path, \"rb\") as f:\n    image_bytes = f.read()\n\nresponse = client.models.generate_content(\n    model=\"gemma-4-26b-a4b-it\",\n    contents=[\n        types.Part.from_bytes(\n            data=image_bytes,\n            mime_type=\"image/jpeg\",\n        ), \n        DRESS_VISION_PROMPT,\n        ],\n        config=types.GenerateContentConfig(\n            response_mime_type=\"application/json\",\n            response_schema=DressVisionMultiResult,\n        ),\n)\n\nprint(response.text)\n```\n\nThis is the model output for the image above\n\n```\n{\n    \"items\":\n    [\n        {\n            \"item_name\": \"light blue blazer\",\n            \"category\": \"outerwear\",\n            \"colors\":\n            [\n                \"#a5c7f7\"\n            ],\n            \"dominant_color\": \"#a5c7f7\",\n            \"warmth_level\": \"medium\",\n            \"season_suitability\":\n            [\n                \"summer\",\n                \"spring\"\n            ],\n            \"style\":\n            [\n                \"smart_casual\"\n            ],\n            \"description\": \"A light blue single-breasted blazer with a pocket square.\",\n            \"layering\": \"outer\",\n            \"pattern\": \"solid\",\n            \"material\": \"linen\",\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"light\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"work\",\n                \"outdoor\"\n            ],\n            \"confidence\": 0.95\n        },\n        {\n            \"item_name\": \"white dress shirt\",\n            \"category\": \"top\",\n            \"colors\":\n            [\n                \"#ffffff\"\n            ],\n            \"dominant_color\": \"#ffffff\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\":\n            [\n                \"summer\",\n                \"spring\"\n            ],\n            \"style\":\n            [\n                \"formal\"\n            ],\n            \"description\": \"A crisp white button-down dress shirt.\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"cotton\",\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"light\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"work\",\n                \"party\"\n            ],\n            \"confidence\": 0.98\n        },\n        {\n            \"item_name\": \"white trousers\",\n            \"category\": \"bottom\",\n            \"colors\":\n            [\n                \"#ffffff\"\n            ],\n            \"dominant_color\": \"#ffffff\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\":\n            [\n                \"summer\",\n                \"spring\"\n            ],\n            \"style\":\n            [\n                \"smart_casual\"\n            ],\n            \"description\": \"A pair of slim-fit white trousers.\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"cotton\",\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"light\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"work\",\n                \"outdoor\"\n            ],\n            \"confidence\": 0.95\n        },\n        {\n            \"item_name\": \"dark brown leather belt\",\n            \"category\": \"accessory\",\n            \"colors\":\n            [\n                \"#3b2b1e\"\n            ],\n            \"dominant_color\": \"#3b2b1e\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\":\n            [\n                \"all_season\"\n            ],\n            \"style\":\n            [\n                \"classic\"\n            ],\n            \"description\": \"A dark brown leather belt with a silver-tone buckle.\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"leather\",\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"dark\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"work\"\n            ],\n            \"confidence\": 0.9\n        },\n        {\n            \"item_name\": \"sunglasses\",\n            \"category\": \"accessory\",\n            \"colors\":\n            [\n                \"#1a1a1a\"\n            ],\n            \"dominant_color\": \"#1a1a1a\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\":\n            [\n                \"summer\"\n            ],\n            \"style\":\n            [\n                \"casual\"\n            ],\n            \"description\": \"Dark sunglasses with black frames.\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": null,\n            \"formality\": \"casual\",\n            \"brightness\": \"dark\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"outdoor\"\n            ],\n            \"confidence\": 0.95\n        },\n        {\n            \"item_name\": \"watch\",\n            \"category\": \"accessory\",\n            \"colors\":\n            [\n                \"#000000\"\n            ],\n            \"dominant_color\": \"#000000\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\":\n            [\n                \"all_season\"\n            ],\n            \"style\":\n            [\n                \"classic\"\n            ],\n            \"description\": \"A black wristwatch with a dark face.\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": null,\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"dark\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"work\"\n            ],\n            \"confidence\": 0.85\n        },\n        {\n            \"item_name\": \"dark brown loafers\",\n            \"category\": \"shoes\",\n            \"colors\":\n            [\n                \"#3d2b1f\"\n            ],\n            \"dominant_color\": \"#3d2b1f\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\":\n            [\n                \"all_season\"\n            ],\n            \"style\":\n            [\n                \"casual\",\n                \"smart_casual\"\n            ],\n            \"description\": \"Dark brown leather loafers.\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"leather\",\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"dark\",\n            \"water_resistant\": false,\n            \"occasion_tags\":\n            [\n                \"outdoor\",\n                \"work\"\n            ],\n            \"confidence\": 0.92\n        }\n    ]\n}\n```\n\nI actually didn't notice the belt and watch, but someone -_- seems to be watching every detail.\n\n## Weather prediction\n\nAfter understanding the user’s clothes, DressCode uses Gemma 4’s function calling capability to handle the second key task. When the user selects a date, time, and city for their event or trip, the model makes a structured function call to fetch accurate weather information.\n\nUsing function calling, Gemma 4 requests real-time weather data for the chosen city and date. It receives details such as temperature, weather conditions (sunny, rainy, cloudy, etc.), and day/night timing. The model then analyzes this data together with the user’s clothing database to intelligently select and combine items.\n\nThis allows Gemma 4 to consider warmth level, season suitability, and weather conditions before generating complete outfit recommendations that match in color, style, and appropriateness.\n\nBy combining powerful image analysis with function calling for live weather, DressCode delivers smart and practical outfit suggestions every time.\n\n``` python\nimport os\nimport requests\nfrom google import genai\nfrom google.genai import types\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\ndef fetch_weather_from_api(location: str) -> dict:\n    \"\"\"Hits Open-Meteo API to get real weather data.\"\"\"\n    try:\n        # First, geocode the city name to get latitude and longitude\n        geo_url = f\"https://geocoding-api.open-meteo.com/v1/search?name={location}&count=1&language=en&format=json\"\n        geo_res = requests.get(geo_url).json()\n\n        if not geo_res.get(\"results\"):\n            return {\"error\": f\"Could not find location: {location}\"}\n\n        lat = geo_res[\"results\"][0][\"latitude\"]\n        lon = geo_res[\"results\"][0][\"longitude\"]\n\n        # Second, get the weather using the coordinates\n        weather_url = f\"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&current=temperature_2m,relative_humidity_2m,precipitation&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_max&timezone=auto\"\n        weather_data = requests.get(weather_url).json()\n\n        return {\n            \"location\": location,\n            \"current_temp_celsius\": weather_data[\"current\"][\"temperature_2m\"],\n            \"current_humidity\": weather_data[\"current\"][\"relative_humidity_2m\"],\n            \"current_precipitation_mm\": weather_data[\"current\"][\"precipitation\"],\n            \"today_max_temp\": weather_data[\"daily\"][\"temperature_2m_max\"][0],\n            \"today_min_temp\": weather_data[\"daily\"][\"temperature_2m_min\"][0],\n            \"rain_chance_percentage\": weather_data[\"daily\"][\"precipitation_probability_max\"][0]\n        }\n    except Exception as e:\n        return {\"error\": f\"Failed to get weather data: {str(e)}\"}\n\n# Map function names to our actual python functions\nAVAILABLE_TOOLS = {\n    \"get_weather\": fetch_weather_from_api\n}\n\nget_weather_declaration = {\n    \"name\": \"get_weather\",\n    \"description\": \"Get current weather for a given location.\",\n    \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"location\": {\n                \"type\": \"string\",\n                \"description\": \"City name, e.g. 'Berlin', 'San Francisco'\",\n            },\n        },\n        \"required\": [\"location\"],\n    },\n}\n\nclient = genai.Client()\ntools = types.Tool(function_declarations=[get_weather_declaration])\nconfig = types.GenerateContentConfig(tools=[tools])\n\nuser_prompt = \"Should I bring an umbrella to Berlin today?\"\nprint(f\"User: {user_prompt}\\n\")\n\n# Turn 1: Ask the model\nresponse = client.models.generate_content(\n    model=\"gemma-4-26b-a4b-it\",\n    contents=user_prompt,\n    config=config,\n)\n\n# If the model decided it needs to use our tool\nif response.function_calls:\n    for fc in response.function_calls:\n        print(f\"🤖 Model requests function: {fc.name} with args {fc.args}\")\n\n        # Execute the actual Python tool\n        tool_to_call = AVAILABLE_TOOLS[fc.name]\n        # Extract location safely from tool arguments\n        tool_output = tool_to_call(location=fc.args[\"location\"])\n        print(f\"🔌 Tool output fetched: {tool_output}\\n\")\n\n        # Turn 2: Send the data back to the model so it can construct its answer\n        final_response = client.models.generate_content(\n            model=\"gemma-4-26b-a4b-it\",\n            contents=[\n                # Include the original prompt context\n                user_prompt, \n                # Include the tool request object the model generated\n                response.candidates[0].content, \n                # Provide the real world answer back matching the function ID\n                types.Part.from_function_response(\n                    name=fc.name,\n                    response={\"result\": tool_output}\n                )\n            ],\n            config=config # Keep tools configuration attached\n        )\n\n        print(f\"🤖 final AI Answer: {final_response.text}\")\nelse:\n    print(f\"🤖 AI Answer: {response.text}\")\n```\n\nSometimes, when trying to call any query `gemma`\n\nwe face this error\n\n```\ngoogle.genai.errors.ServerError: 500 INTERNAL. {'error': {'code': 500, 'message': 'Internal error encountered.', 'status': 'INTERNAL'}}\n```\n\nI guess it is due to high demand that the servers sometimes fail. Just trying again usually works.\n\n```\nUser: Should I bring an umbrella to Berlin today?                                 \n\n🤖 Model requests function: get_weather with args {'location': 'Berlin'}\n🔌 Tool output fetched: {'location': 'Berlin', 'current_temp_celsius': 13.8, 'current_humidity': 94, 'current_precipitation_mm': 0.0, 'today_max_temp': 19.5, 'today_min_temp': 13.8, 'rain_chance_percentage': 83}\n\n🤖 final AI Answer: Yes, you should definitely bring an umbrella. There is an 83% chance of rain in Berlin today.\n```\n\nNow, since we can get the weather prediction accurately, we need to write the outfit suggestion prompt\n\n## Outfit suggestion, put it all together\n\nI've written this prompt for outfit suggestion\n\n```\nOUTFIT_SUGGESTION_PROMPT = \"\"\"You are a personal stylist. Pick complete outfits from the user's wardrobe for a specific event.\n\nWorkflow:\n1. Call the `get_weather` function for the event city, passing the event date in ISO YYYY-MM-DD format, to retrieve the forecast (temperature, precipitation, wind, sunrise, sunset).\n2. Consider the event_type, the date (season), the start_time / end_time (whether it falls during the day, night, or spans both around sunrise/sunset), and the weather.\n3. Pick pieces ONLY from the provided wardrobe catalog using their integer `id`. Never invent items.\n4. Build AT LEAST 2 distinct complete outfits. A complete outfit covers, at minimum, a top, a bottom, and shoes when matching items exist in the catalog (a single `dress` category item replaces top+bottom). Add an outerwear piece when the forecast is cold, wet, or windy. Add accessories or bag/hat when appropriate.\n5. Match formality to the event_type:\n   - business / formal -> formality \"business\" or \"formal\"\n   - smart_casual / date_night -> \"smart_casual\" or higher\n   - casual / outdoor / sports / party -> \"casual\" or \"smart_casual\" as fits\n6. Match warmth to the weather. Prefer water-resistant items if rain is likely. Prefer the right season_suitability for the event date.\n7. Ensure COLOR HARMONY across the pieces in each outfit. Use the hex colors in the catalog to reason about complementary, analogous, monochromatic, or neutral-anchor palettes. Briefly state the harmony you chose in `color_harmony`.\n8. Provide a short `weather_summary` of the conditions you optimized for and a per-outfit `reasoning`.\n\nReturn ONLY the structured JSON matching the response schema.\n\"\"\"\n```\n\nAnd for the weather prediction, we need to get it for a certain date, so I've updated it to\n\n``` php\ndef fetch_weather_from_api(location: str, date: str = None) -> dict:\n    \"\"\"Hits Open-Meteo API to get real weather data, optionally for a specific date.\"\"\"\n    try:\n        # 1. Geocode the city name to get latitude and longitude\n        geo_url = f\"https://geocoding-api.open-meteo.com/v1/search?name={location}&count=1&language=en&format=json\"\n        geo_res = requests.get(geo_url).json()\n\n        if not geo_res.get(\"results\"):\n            return {\"error\": f\"Could not find location: {location}\"}\n\n        lat = geo_res[\"results\"][0][\"latitude\"]\n        lon = geo_res[\"results\"][0][\"longitude\"]\n\n        # 2. Build the weather URL based on whether a date was provided\n        # Open-Meteo takes start_date and end_date in YYYY-MM-DD format for specific ranges\n        base_url = f\"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&timezone=auto\"\n\n        if date:\n            weather_url = f\"{base_url}&start_date={date}&end_date={date}&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_max\"\n        else:\n            # Fallback to current/today's forecast if no date is provided\n            weather_url = f\"{base_url}&current=temperature_2m,relative_humidity_2m,precipitation&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_max\"\n\n        weather_data = requests.get(weather_url).json()\n\n        # If there's an API error response from open-meteo\n        if \"error\" in weather_data:\n            return {\"error\": weather_data[\"reason\"]}\n\n        # 3. Format response dynamically depending on what parameters were sent\n        response = {\n            \"location\": location,\n            \"date\": date if date else \"today\",\n            \"today_max_temp\": weather_data[\"daily\"][\"temperature_2m_max\"][0],\n            \"today_min_temp\": weather_data[\"daily\"][\"temperature_2m_min\"][0],\n            \"rain_chance_percentage\": weather_data[\"daily\"][\"precipitation_probability_max\"][0]\n        }\n\n        # Only add current conditions if we didn't look up a specific forecast date\n        if \"current\" in weather_data:\n            response.update({\n                \"current_temp_celsius\": weather_data[\"current\"][\"temperature_2m\"],\n                \"current_humidity\": weather_data[\"current\"][\"relative_humidity_2m\"],\n                \"current_precipitation_mm\": weather_data[\"current\"][\"precipitation\"],\n            })\n\n        return response\n\n    except Exception as e:\n        return {\"error\": f\"Failed to get weather data: {str(e)}\"}\n\n# Map function names to our actual python functions\nAVAILABLE_TOOLS = {\n    \"get_weather\": fetch_weather_from_api\n}\n\n# Updated declaration schema to include the date parameter\nget_weather_declaration = {\n    \"name\": \"get_weather\",\n    \"description\": \"Get current or predicted weather for a given location and optional date.\",\n    \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"location\": {\n                \"type\": \"string\",\n                \"description\": \"City name, e.g. 'Berlin', 'San Francisco'\",\n            },\n            \"date\": {\n                \"type\": \"string\",\n                \"description\": \"The specific date for the weather prediction in YYYY-MM-DD format. Optional: default to today if not provided.\",\n            }\n        },\n        \"required\": [\"location\"],\n    },\n}\n```\n\nNow the user is expected to provide the event details and a list of clothes (catalog). The event will be something like\n\n```\nevent_payload = {\n    \"event_type\": \"casual\",\n    \"event_date\": \"2026-06-01\",\n    \"start_time\": None,\n    \"end_time\": None,\n    \"city\": \"Berlin\",\n    \"season\": \"Spring\",\n    \"title\": \"Walk in the park\",\n    \"notes\": \"\",\n}\n```\n\nand the catalog will be a list of clothes from analyzing the images\n\n```\ncatalog = [\n        {\n            \"item_name\": \"light blue blazer\",\n            \"category\": \"outerwear\",\n            \"colors\":\n            [\n                \"#a5c7f7\"\n            ],\n            \"dominant_color\": \"#a5c7f7\",\n            ...\n```\n\nThe final user prompt would look like\n\n```\nuser_prompt = (\n            f\"{OUTFIT_SUGGESTION_PROMPT}\\n\\n\"\n            f\"Event:\\n{json.dumps(event_payload, indent=2)}\\n\\n\"\n            f\"Wardrobe catalog ({len(catalog)} items):\\n\"\n            f\"{json.dumps([c for c in catalog], indent=2)}\"\n        )\n```\n\nWill it work? let's try it out\n\n```\n{\n    \"weather_summary\": \"A warm and sunny spring day with a high of 29.9°C and a low of 16.4°C. Low chance of rain (16%), making it perfect for light, breathable fabrics and outdoor activities.\",\n    \"color_harmony\": \"I utilized a palette of crisp whites and light blues anchored by deep brown leather tones to create a refreshing, airy, and sophisticated summer-ready look.\",\n    \"outfits\":\n    [\n        {\n            \"outfit_id\": 1,\n            \"items\":\n            [\n                1,\n                2,\n                4,\n                5,\n                6\n            ],\n            \"reasoning\": \"This outfit is optimized for the warm peak temperatures. The all-white base (shirt and trousers) reflects sunlight to keep you cool during your walk. I've added sunglasses and a watch to keep the look effortless and casual for a park setting.\"\n        },\n        {\n            \"outfit_id\": 2,\n            \"items\":\n            [\n                0,\n                1,\n                2,\n                3,\n                6\n            ],\n            \"reasoning\": \"For a slightly more elevated 'smart-casual' approach, I've layered the light blue linen blazer. The linen material is highly breathable for the 29°C weather, and the light blue complements the white base perfectly. The dark brown belt and loafers provide a classic, grounded finish.\"\n        }\n    ]\n}\n```\n\nInteresting choices, especially since the closet we use is almost empty.\n\n## In short!\n\nDressCode is a complete pipeline that intelligently recommends outfits based on your actual wardrobe and upcoming weather conditions. Built with a focus on simplicity and efficiency, the system uses Gemma 4 as its core AI engine and runs inside a UV virtual environment.\n\nBased on our experiments in this article, the core proof of concept was built on those steps\n\nWardrobe Ingestion\n\nUsers place photos of their clothes in a folder called catalog. The application scans this folder and uses Gemma 4 to analyze each image. For every photo (e.g., red_jacket.jpg), it generates a detailed JSON description file (red_jacket.json) containing the item’s name, colors, warmth level, season suitability, style tags, category, and rich visual description. If a matching JSON file already exists, the image is skipped to avoid redundant AI calls.Event Definition\n\nThe user defines their plans by creating a simple event.json file containing the event title, date, time range, location, and occasion type.Weather Integration\n\nThe system automatically fetches accurate weather forecast data for the specified date and location.Intelligent Outfit Generation\n\nDressCode reads all the clothing descriptions from the catalog folder, filters out unsuitable items (wrong season, inadequate warmth, or mismatched style), and feeds the relevant clothing data along with the weather information and event details to Gemma 4. The model then generates well-coordinated outfit suggestions, taking into account color harmony, layering needs, day/night conditions, and the specific occasion.\n\nA sample of the system outfit suggestions\n\nThese outfit suggestions were generated from the clothes images\n\n| graphic t-shirt (top) | grey sweat shorts (bottom) | navy blue lightning bolt sneakers (shoes) |\n|---|---|---|\n\n| wide brim sun hat (hat) | short sleeve shirt (top) | light blue pleated trousers (bottom) |\n|---|---|---|\n\nWe learn from the **\"short sleeve shirt (top)\"** that the AI can sometimes only see the tops of things, just like us humans :D. So don't trust everything you see, even Gemma can make mistakes\n\nNotice that I didn't feed the images to the image-generation model but only the outfit description model. In an actual app, it would be nice to provide both clothes images and a user profile, and ask the image-generation models to generate the complete outfit.\n\nActually, the profile image should be a full-body image of the user, so the app can show exactly how the suggested outfit will look on them.\n\n```\n{\n  \"event\": {\n    \"event_type\": \"casual\",\n    \"event_date\": \"2026-06-01\",\n    \"start_time\": null,\n    \"end_time\": null,\n    \"city\": \"Berlin\",\n    \"season\": \"summer\",\n    \"title\": \"Walk in the park\",\n    \"notes\": \"\"\n  },\n  \"season\": \"summer\",\n  \"filtered_item_count\": 11,\n  \"weather_summary\": \"Warm summer day with a high of 29.9\\u00b0C and low of 16.4\\u00b0C. Very low chance of rain and light winds.\",\n  \"outfits\": [\n    {\n      \"name\": \"Sunny Park Casual\",\n      \"color_harmony\": \"A light, airy palette using beige (#e6e1d3) and light blue (#8eb0d4) with navy accents (#001a33) for a cohesive, summery feel.\",\n      \"reasoning\": \"Perfect for a warm summer walk in the park. The linen-blend trousers and short-sleeve shirt are breathable for the 30\\u00b0C high, while the sun hat provides protection.\",\n      \"pieces\": [\n        {\n          \"dress_id\": 3,\n          \"category\": \"top\",\n          \"role\": \"top\",\n          \"source_image\": \"2ce384fd55b44d16bcc9bb3c12c9bf4a.webp\",\n          \"item\": {\n            \"id\": 3,\n            \"item_name\": \"short sleeve shirt\",\n            \"category\": \"top\",\n            \"colors\": [\n              \"#e6e1d3\"\n            ],\n            \"dominant_color\": \"#e6e1d3\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\": [\n              \"summer\",\n              \"spring\"\n            ],\n            \"style\": [\n              \"casual\"\n            ],\n            \"formality\": \"casual\",\n            \"brightness\": \"light\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"linen\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"daily\"\n            ],\n            \"description\": \"A light beige, short sleeve button-down shirt made of a lightweight fabric.\"\n          }\n        },\n        {\n          \"dress_id\": 14,\n          \"category\": \"bottom\",\n          \"role\": \"bottom\",\n          \"source_image\": \"spc2402.webp\",\n          \"item\": {\n            \"id\": 14,\n            \"item_name\": \"light blue pleated trousers\",\n            \"category\": \"bottom\",\n            \"colors\": [\n              \"#8eb0d4\"\n            ],\n            \"dominant_color\": \"#8eb0d4\",\n            \"warmth_level\": \"medium\",\n            \"season_suitability\": [\n              \"spring\",\n              \"summer\",\n              \"fall\"\n            ],\n            \"style\": [\n              \"casual\",\n              \"relaxed\"\n            ],\n            \"formality\": \"smart_casual\",\n            \"brightness\": \"light\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"linen blend\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"daily wear\",\n              \"summer outings\"\n            ],\n            \"description\": \"A pair of light blue trousers with a pleated front and an elasticated drawstring waist. The fabric appears to be a lightweight linen or cotton blend.\"\n          }\n        },\n        {\n          \"dress_id\": 7,\n          \"category\": \"shoes\",\n          \"role\": \"shoes\",\n          \"source_image\": \"Buy-Best-Quality-IMPORTED-Full-Blue-Shoes-for-Men-NB02-at-Most-Affordable-Price-by-shopse.pk-in-Pakistan-1-1200x900.jpg\",\n          \"item\": {\n            \"id\": 7,\n            \"item_name\": \"navy blue lightning bolt sneakers\",\n            \"category\": \"shoes\",\n            \"colors\": [\n              \"#1e3a5f\",\n              \"#ffffff\"\n            ],\n            \"dominant_color\": \"#1e3a5f\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\": [\n              \"all_season\"\n            ],\n            \"style\": [\n              \"streetwear\",\n              \"casual\"\n            ],\n            \"formality\": \"casual\",\n            \"brightness\": \"mixed\",\n            \"layering\": \"base\",\n            \"pattern\": \"graphic\",\n            \"material\": \"synthetic\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"lifestyle\",\n              \"streetwear\"\n            ],\n            \"description\": \"Navy blue sneakers with a large white lightning bolt graphic on the side and a thick platform sole.\"\n          }\n        },\n        {\n          \"dress_id\": 10,\n          \"category\": \"hat\",\n          \"role\": \"accessory\",\n          \"source_image\": \"damenhut-elegant-blau-strohhut-sommer-s2024tiffany-11.282x0-portrait.jpg\",\n          \"item\": {\n            \"id\": 10,\n            \"item_name\": \"wide brim sun hat\",\n            \"category\": \"hat\",\n            \"colors\": [\n              \"#001a33\"\n            ],\n            \"dominant_color\": \"#001a33\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\": [\n              \"summer\",\n              \"spring\"\n            ],\n            \"style\": [\n              \"elegant\",\n              \"classic\"\n            ],\n            \"formality\": \"formal\",\n            \"brightness\": \"dark\",\n            \"layering\": \"outer\",\n            \"pattern\": \"solid\",\n            \"material\": \"straw\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"outdoor\",\n              \"garden party\"\n            ],\n            \"description\": \"A large navy blue wide brim hat with a decorative band and a bow on the side.\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Relaxed Summer Blue\",\n      \"color_harmony\": \"Monochromatic-leaning blue tones with neutral grey (#808080) as an anchor.\",\n      \"reasoning\": \"A very casual, comfortable option for walking. The graphic tee and sweat shorts are ideal for high temperatures, and the sneakers are perfect for a park stroll.\",\n      \"pieces\": [\n        {\n          \"dress_id\": 1,\n          \"category\": \"top\",\n          \"role\": \"top\",\n          \"source_image\": \"0d93ccd6fd86dd88dbf1127957054b4f__384.webp\",\n          \"item\": {\n            \"id\": 1,\n            \"item_name\": \"graphic t-shirt\",\n            \"category\": \"top\",\n            \"colors\": [\n              \"#a1c4fd\"\n            ],\n            \"dominant_color\": \"#a1c4fd\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\": [\n              \"summer\",\n              \"spring\"\n            ],\n            \"style\": [\n              \"casual\",\n              \"streetwear\"\n            ],\n            \"formality\": \"casual\",\n            \"brightness\": \"light\",\n            \"layering\": \"base\",\n            \"pattern\": \"graphic\",\n            \"material\": \"cotton\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"birthday\",\n              \"casual\"\n            ],\n            \"description\": \"A light blue short-sleeve t-shirt featuring a large black graphic text that says 'IT TOOK ME 30 Years to look this GOOD'.\"\n          }\n        },\n        {\n          \"dress_id\": 4,\n          \"category\": \"bottom\",\n          \"role\": \"bottom\",\n          \"source_image\": \"4_97683d58-4c20-474b-b247-2b952b726a65.webp\",\n          \"item\": {\n            \"id\": 4,\n            \"item_name\": \"grey sweat shorts\",\n            \"category\": \"bottom\",\n            \"colors\": [\n              \"#808080\",\n              \"#ffffff\"\n            ],\n            \"dominant_color\": \"#808080\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\": [\n              \"summer\",\n              \"spring\"\n            ],\n            \"style\": [\n              \"casual\",\n              \"streetwear\"\n            ],\n            \"formality\": \"casual\",\n            \"brightness\": \"mixed\",\n            \"layering\": \"base\",\n            \"pattern\": \"solid\",\n            \"material\": \"cotton\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"lounging\",\n              \"outdoor\",\n              \"gym\"\n            ],\n            \"description\": \"A pair of grey marl sweat shorts with an elasticated waistband and white drawstrings.\"\n          }\n        },\n        {\n          \"dress_id\": 7,\n          \"category\": \"shoes\",\n          \"role\": \"shoes\",\n          \"source_image\": \"Buy-Best-Quality-IMPORTED-Full-Blue-Shoes-for-Men-NB02-at-Most-Affordable-Price-by-shopse.pk-in-Pakistan-1-1200x900.jpg\",\n          \"item\": {\n            \"id\": 7,\n            \"item_name\": \"navy blue lightning bolt sneakers\",\n            \"category\": \"shoes\",\n            \"colors\": [\n              \"#1e3a5f\",\n              \"#ffffff\"\n            ],\n            \"dominant_color\": \"#1e3a5f\",\n            \"warmth_level\": \"light\",\n            \"season_suitability\": [\n              \"all_season\"\n            ],\n            \"style\": [\n              \"streetwear\",\n              \"casual\"\n            ],\n            \"formality\": \"casual\",\n            \"brightness\": \"mixed\",\n            \"layering\": \"base\",\n            \"pattern\": \"graphic\",\n            \"material\": \"synthetic\",\n            \"water_resistant\": false,\n            \"occasion_tags\": [\n              \"lifestyle\",\n              \"streetwear\"\n            ],\n            \"description\": \"Navy blue sneakers with a large white lightning bolt graphic on the side and a thick platform sole.\"\n          }\n        }\n      ]\n    }\n  ],\n  \"generated_at\": \"2026-05-22T14:54:07.319053+00:00\"\n}\n```\n\nUnfortunately, Gemma can't generate images :(. So we ask Google to pay more attention to image generation next time. I really liked the idea of Gemini Omni (all-to-all model); it sounds like magic, and I cannot wait to get my hands on it!\n\nDid you like the idea? Would you like to build the complete app?\n\nContact me here and show your support at\n\nthe core code [repo](https://github.com/saad4software/dresscode-core)\n\nand the backend code [repo](https://github.com/saad4software/dresscode-back)", "url": "https://wpnews.pro/news/dresscode-your-ai-stylist-for-tomorrow", "canonical_source": "https://dev.to/saad4software/dresscode-your-ai-stylist-for-tomorrow-2m26", "published_at": "2026-05-22 15:59:28+00:00", "updated_at": "2026-05-22 16:02:50.963761+00:00", "lang": "en", "topics": ["artificial-intelligence", "products", "developer-tools"], "entities": ["DressCode", "Gemma 4", "Google"], "alternates": {"html": "https://wpnews.pro/news/dresscode-your-ai-stylist-for-tomorrow", "markdown": "https://wpnews.pro/news/dresscode-your-ai-stylist-for-tomorrow.md", "text": "https://wpnews.pro/news/dresscode-your-ai-stylist-for-tomorrow.txt", "jsonld": "https://wpnews.pro/news/dresscode-your-ai-stylist-for-tomorrow.jsonld"}}