hua101's picture
Update app.py
8372def verified
# 免費版台灣上班族穿搭建議系統
# 不需要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)