# 免費版台灣上班族穿搭建議系統 # 不需要HuggingFace額度,純本地運行 import gradio as gr from smolagents import tool # 工具1:天氣權重計算 @tool def calculate_weather_impact(temperature: float, humidity: float, rain_chance: float, uv_index: int) -> dict: """ 計算天氣因素對穿著的影響權重 Args: temperature (float): 當前溫度,單位攝氏度,範圍-10到50 humidity (float): 當前濕度百分比,範圍0到100 rain_chance (float): 降雨機率百分比,範圍0到100 uv_index (int): 紫外線指數,範圍0到15 Returns: dict: 包含各種天氣影響權重的字典 """ # 錯誤檢查 if temperature < -10 or temperature > 50: return {"error": "溫度範圍應在-10°C到50°C之間"} if humidity < 0 or humidity > 100: return {"error": "濕度應在0%到100%之間"} if rain_chance < 0 or rain_chance > 100: return {"error": "降雨機率應在0%到100%之間"} if uv_index < 0 or uv_index > 15: return {"error": "紫外線指數應在0到15之間"} # 台灣氣候特性權重計算 weights = {} # 溫度權重 (台灣標準) if temperature <= 15: weights["temperature_level"] = "寒冷" weights["warmth_need"] = 0.9 elif temperature <= 20: weights["temperature_level"] = "涼爽" weights["warmth_need"] = 0.6 elif temperature <= 28: weights["temperature_level"] = "舒適" weights["warmth_need"] = 0.3 elif temperature <= 35: weights["temperature_level"] = "炎熱" weights["warmth_need"] = 0.1 else: weights["temperature_level"] = "酷熱" weights["warmth_need"] = 0.0 # 濕度權重 if humidity >= 80: weights["humidity_level"] = "非常潮濕" weights["breathability_need"] = 0.9 elif humidity >= 70: weights["humidity_level"] = "潮濕" weights["breathability_need"] = 0.7 elif humidity >= 60: weights["humidity_level"] = "適中" weights["breathability_need"] = 0.5 else: weights["humidity_level"] = "乾燥" weights["breathability_need"] = 0.3 # 降雨權重 if rain_chance >= 70: weights["rain_level"] = "大雨機率" weights["waterproof_need"] = 0.9 elif rain_chance >= 30: weights["rain_level"] = "可能下雨" weights["waterproof_need"] = 0.6 else: weights["rain_level"] = "晴天" weights["waterproof_need"] = 0.2 # 紫外線權重 if uv_index >= 8: weights["uv_level"] = "過量" weights["sun_protection_need"] = 0.9 elif uv_index >= 6: weights["uv_level"] = "高" weights["sun_protection_need"] = 0.7 elif uv_index >= 3: weights["uv_level"] = "中等" weights["sun_protection_need"] = 0.4 else: weights["uv_level"] = "低" weights["sun_protection_need"] = 0.2 return weights # 工具2:身體狀況分析 @tool def analyze_body_condition(gender: str, body_temp: float, cold_sensitivity: str, activity_level: str) -> dict: """ 分析個人身體狀況對穿著的影響 Args: gender (str): 性別,選擇"男性"或"女性" body_temp (float): 當前體溫,單位攝氏度,正常範圍35.0-42.0 cold_sensitivity (str): 體質類型,選擇"怕冷"、"正常"或"怕熱" activity_level (str): 工作活動量,選擇"久坐"、"一般"或"頻繁走動" Returns: dict: 包含個人狀況分析結果的字典 """ if gender not in ["男性", "女性"]: return {"error": "性別請選擇:男性 或 女性"} if body_temp < 35.0 or body_temp > 42.0: return {"error": "體溫範圍應在35.0°C到42.0°C之間"} if cold_sensitivity not in ["怕冷", "正常", "怕熱"]: return {"error": "體質請選擇:怕冷、正常、怕熱"} if activity_level not in ["久坐", "一般", "頻繁走動"]: return {"error": "活動量請選擇:久坐、一般、頻繁走動"} condition = {} # 體溫調整 if body_temp >= 38.0: condition["health_status"] = "發燒" condition["extra_warmth"] = 0.8 elif body_temp <= 36.0: condition["health_status"] = "體溫偏低" condition["extra_warmth"] = 0.7 else: condition["health_status"] = "正常" condition["extra_warmth"] = 0.0 # 體質調整 sensitivity_adjustment = { "怕冷": 0.3, "正常": 0.0, "怕熱": -0.3 } condition["sensitivity_adjustment"] = sensitivity_adjustment[cold_sensitivity] # 活動量調整 activity_adjustment = { "久坐": 0.2, "一般": 0.0, "頻繁走動": -0.2 } condition["activity_adjustment"] = activity_adjustment[activity_level] # 性別考量 if gender == "女性": condition["style_options"] = ["裙裝", "褲裝", "洋裝"] else: condition["style_options"] = ["西裝", "商務休閒"] return condition # 工具3:穿搭建議生成 @tool def generate_outfit_recommendation(weather_weights: dict, body_condition: dict, meeting_importance: str) -> str: """ 生成完整的穿搭建議 Args: weather_weights (dict): 天氣權重分析結果 body_condition (dict): 身體狀況分析結果 meeting_importance (str): 會議重要性,選擇"一般上班"、"重要會議"或"客戶拜訪" Returns: str: 完整的穿搭建議文字 """ if "error" in weather_weights: return f"天氣數據錯誤:{weather_weights['error']}" if "error" in body_condition: return f"身體狀況錯誤:{body_condition['error']}" if meeting_importance not in ["一般上班", "重要會議", "客戶拜訪"]: return "會議重要性請選擇:一般上班、重要會議、客戶拜訪" # 計算總體保暖需求 total_warmth_need = ( weather_weights.get("warmth_need", 0.5) + body_condition.get("extra_warmth", 0.0) + body_condition.get("sensitivity_adjustment", 0.0) + body_condition.get("activity_adjustment", 0.0) ) # 限制在0-1範圍內 total_warmth_need = max(0.0, min(1.0, total_warmth_need)) # 上衣建議 if total_warmth_need >= 0.8: upper_wear = ["厚外套", "毛衣", "長袖襯衫"] elif total_warmth_need >= 0.6: upper_wear = ["薄外套", "長袖襯衫", "針織衫"] elif total_warmth_need >= 0.4: upper_wear = ["長袖襯衫", "薄針織衫"] elif total_warmth_need >= 0.2: upper_wear = ["短袖襯衫", "薄長袖"] else: upper_wear = ["短袖襯衫", "無袖上衣"] # 下裝建議 gender = "女性" if "裙裝" in body_condition.get("style_options", []) else "男性" if gender == "女性": if total_warmth_need >= 0.6: lower_wear = ["長褲", "長裙配絲襪"] elif weather_weights.get("rain_level") == "大雨機率": lower_wear = ["長褲"] else: lower_wear = ["長褲", "及膝裙", "長裙"] else: lower_wear = ["長褲"] # 外套建議 outer_wear = [] if weather_weights.get("waterproof_need", 0) >= 0.6: outer_wear.append("防水外套或雨傘") if total_warmth_need >= 0.7: outer_wear.append("保暖外套") # 配件建議 accessories = [] if weather_weights.get("sun_protection_need", 0) >= 0.7: accessories.append("防曬乳、太陽眼鏡") if weather_weights.get("rain_level") == "大雨機率": accessories.append("雨傘、防水鞋") if total_warmth_need >= 0.8: accessories.append("圍巾、手套") # 根據會議重要性調整 formality_note = "" if meeting_importance == "重要會議": formality_note = "\n⚠️ 重要會議建議:選擇較正式的款式,避免過於休閒的搭配" elif meeting_importance == "客戶拜訪": formality_note = "\n⚠️ 客戶拜訪建議:選擇專業形象,注意配色協調" # 組合建議 result = f"🌤️ 今日穿搭建議 (保暖需求指數: {total_warmth_need:.1f})\n\n" result += f"👔 上衣:{' 或 '.join(upper_wear)}\n" result += f"👖 下裝:{' 或 '.join(lower_wear)}\n" if outer_wear: result += f"🧥 外套:{' + '.join(outer_wear)}\n" if accessories: result += f"👜 配件:{' + '.join(accessories)}\n" # 天氣提醒 result += f"\n🌡️ 天氣提醒:\n" result += f"- 溫度感受:{weather_weights.get('temperature_level', '未知')}\n" result += f"- 濕度狀況:{weather_weights.get('humidity_level', '未知')}\n" result += f"- 降雨機率:{weather_weights.get('rain_level', '未知')}\n" result += f"- 紫外線:{weather_weights.get('uv_level', '未知')}\n" # 個人化提醒 if body_condition.get("health_status") != "正常": result += f"\n🏥 健康提醒:{body_condition['health_status']},建議多注意保暖\n" result += formality_note return result # 免費版穿搭顧問類別 (不需要LLM) class FreeOutfitAdvisor: """免費版穿搭顧問,無需LLM額度""" def __init__(self): self.tools = { 'weather': calculate_weather_impact, 'body': analyze_body_condition, 'outfit': generate_outfit_recommendation } def get_recommendation(self, temp, humidity, rain, uv, gender, body_temp, sensitivity, activity, meeting): """獲取穿搭建議""" weather_result = self.tools['weather'](temp, humidity, rain, uv) body_result = self.tools['body'](gender, body_temp, sensitivity, activity) recommendation = self.tools['outfit'](weather_result, body_result, meeting) return recommendation # 創建全域顧問實例 advisor = FreeOutfitAdvisor() # Gradio 介面函數 def outfit_advice_interface(temperature, humidity, rain_chance, uv_index, gender, body_temp, cold_sensitivity, activity_level, meeting_importance): """Gradio 介面主函數""" try: result = advisor.get_recommendation( temp=float(temperature), humidity=float(humidity), rain=float(rain_chance), uv=int(uv_index), gender=gender, body_temp=float(body_temp), sensitivity=cold_sensitivity, activity=activity_level, meeting=meeting_importance ) return result except Exception as e: return f"❌ 發生錯誤:{str(e)}\n請檢查輸入數值是否正確。" # 創建 Gradio 介面 with gr.Blocks(title="台灣上班族穿搭AI顧問", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🎯 台灣上班族穿搭AI顧問") gr.Markdown("根據天氣、個人狀況和工作需求,為您量身打造最適合的穿搭建議!") with gr.Row(): with gr.Column(): gr.Markdown("## 🌤️ 天氣資訊") temperature = gr.Slider( minimum=-10, maximum=50, value=25, step=0.5, label="溫度 (°C)", info="當前溫度" ) humidity = gr.Slider( minimum=0, maximum=100, value=70, step=1, label="濕度 (%)", info="空氣濕度百分比" ) rain_chance = gr.Slider( minimum=0, maximum=100, value=30, step=5, label="降雨機率 (%)", info="今日降雨可能性" ) uv_index = gr.Slider( minimum=0, maximum=15, value=5, step=1, label="紫外線指數", info="UV指數 (0-15)" ) with gr.Column(): gr.Markdown("## 👤 個人資訊") gender = gr.Radio( choices=["男性", "女性"], value="女性", label="性別", info="影響穿搭風格選擇" ) body_temp = gr.Slider( minimum=35.0, maximum=42.0, value=36.5, step=0.1, label="體溫 (°C)", info="當前體溫狀況" ) cold_sensitivity = gr.Radio( choices=["怕冷", "正常", "怕熱"], value="正常", label="體質類型", info="個人冷熱感受" ) activity_level = gr.Radio( choices=["久坐", "一般", "頻繁走動"], value="一般", label="工作活動量", info="今日活動程度" ) meeting_importance = gr.Radio( choices=["一般上班", "重要會議", "客戶拜訪"], value="一般上班", label="會議重要性", info="影響正式程度" ) with gr.Row(): submit_btn = gr.Button("🎯 生成穿搭建議", variant="primary", size="lg") clear_btn = gr.Button("🔄 重置", variant="secondary", size="lg") with gr.Row(): output = gr.Textbox( label="📋 穿搭建議結果", lines=15, max_lines=20, placeholder="點擊「生成穿搭建議」按鈕來獲取個人化建議..." ) # 按鈕事件 submit_btn.click( fn=outfit_advice_interface, inputs=[ temperature, humidity, rain_chance, uv_index, gender, body_temp, cold_sensitivity, activity_level, meeting_importance ], outputs=output ) clear_btn.click( fn=lambda: [25, 70, 30, 5, "女性", 36.5, "正常", "一般", "一般上班", ""], outputs=[ temperature, humidity, rain_chance, uv_index, gender, body_temp, cold_sensitivity, activity_level, meeting_importance, output ] ) # 預設示例 gr.Markdown("## 💡 使用提示") gr.Markdown(""" - **天氣資訊**:可參考氣象局或天氣App的數據 - **個人資訊**:根據實際狀況調整,體溫正常範圍35-37°C - **會議重要性**:影響穿搭的正式程度選擇 - **系統特色**:專為台灣氣候和上班族需求設計 """) # 啟動應用 if __name__ == "__main__": demo.launch(share=True)