# ui/renderers.py from typing import Union from datetime import datetime from config import AGENTS_INFO import json def _format_location(loc_data) -> str: if isinstance(loc_data, dict): return f"{loc_data.get('lat', 0):.4f}, {loc_data.get('lng', 0):.4f}" if isinstance(loc_data, str) and "lat" in loc_data: try: # 嘗試把單引號換雙引號解析,解析失敗就回傳原字串 clean = loc_data.replace("'", '"') data = json.loads(clean) return f"{data.get('lat', 0):.2f}, {data.get('lng', 0):.2f}" except: pass return str(loc_data) def _format_iso_time(iso_str: str) -> str: if not iso_str or iso_str == "N/A": return "" try: dt = datetime.fromisoformat(iso_str) return dt.strftime("%H:%M") except Exception: if "T" in iso_str: return iso_str.split("T")[1][:5] return iso_str def create_agent_stream_output(text: str = None) -> str: return f'
{text}
' def create_agent_dashboard(status_dict: dict) -> str: # 定義順序 order = ['team', 'scout', 'weatherman', 'optimizer', 'navigator', 'presenter'] cards_html = "" for key in order: info = AGENTS_INFO.get(key, {}) state = status_dict.get(key, {}) status = state.get('status', 'idle') msg = state.get('message', 'Standby') is_working = status == 'working' css_class = "working" if is_working else "" icon = info.get('icon', '🤖') name = info.get('name', key.title()) # 簡單的卡片結構 cards_html += f"""
{icon}
{name}
{msg}
""" return f'
{cards_html}
' html = f"""
{_render_card(leader_key)}
{''.join([_render_card(k) for k in member_keys])}
""" return html def create_summary_card(total_tasks, high_priority, total_time, location="Taipei", date="Today") -> str: clean_loc = _format_location(location) # 這裡的 HTML 結構很單純,不會破壞佈局 return f"""
TRIP SUMMARY
📍 {clean_loc}
📅 {date}
{total_tasks} Tasks
{total_time}mins Duration
{high_priority} High Prio
""" def create_task_card(task_num, task_title, priority, time_window, duration, location, icon="📋") -> str: p_cls = priority.lower() # high, medium, low # --- 🔥 恢復 Time Window 邏輯 --- display_time = "Anytime" if isinstance(time_window, dict): s_clean = _format_iso_time(time_window.get('earliest_time', '')) e_clean = _format_iso_time(time_window.get('latest_time', '')) if s_clean and e_clean: display_time = f"{s_clean} - {e_clean}" elif s_clean: display_time = f"After {s_clean}" elif e_clean: display_time = f"Before {e_clean}" elif time_window: display_time = str(time_window) # ------------------------------- return f"""
{icon} {task_title} {priority}
📍 {location}
🕒 {display_time} | ⏳ {duration}
""" # 🔥🔥🔥 Updated Timeline Function def create_timeline_html_enhanced(timeline): if not timeline: return """
No timeline data available yet.
""" html = '
' for i, stop in enumerate(timeline): location = stop.get('location', 'Unknown') time_str = stop.get('time', '') if not time_str or time_str == "N/A": time_str = "Flexible Time" weather_str = stop.get('weather', '') weather_html = "" if weather_str and weather_str != "N/A": weather_html = f'
🌤️ {weather_str}
' html += f"""
{location}
🕒 {time_str}
{weather_html}
""" html += '
' return html # Empty Placeholders def create_metrics_cards(metrics, traffic): return "" def create_result_visualization(tasks, data): return "" def generate_chat_history_html_bubble(session): return ""