Spaces:
Sleeping
Sleeping
| # 免費版台灣上班族穿搭建議系統 | |
| # 不需要HuggingFace額度,純本地運行 | |
| import gradio as gr | |
| from smolagents import tool | |
| # 工具1:天氣權重計算 | |
| 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:身體狀況分析 | |
| 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:穿搭建議生成 | |
| 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) |