Spaces:
Running
Running
| # 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'<div style="font-family: monospace; color: #334155;">{text}</div>' | |
| 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""" | |
| <div class="agent-status-card {css_class}"> | |
| <div class="agent-icon">{icon}</div> | |
| <div class="agent-info"> | |
| <div class="agent-name">{name}</div> | |
| <div class="agent-msg">{msg}</div> | |
| </div> | |
| </div> | |
| """ | |
| return f'<div class="agent-status-row">{cards_html}</div>' | |
| html = f""" | |
| <div class="agent-war-room"> | |
| <div class="org-chart"> | |
| <div class="org-level"> | |
| {_render_card(leader_key)} | |
| </div> | |
| <div class="connector-line"></div> | |
| <div class="connector-horizontal"></div> | |
| <div class="org-level"> | |
| {''.join([_render_card(k) for k in member_keys])} | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| 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""" | |
| <div class="summary-card-modern"> | |
| <div class="summary-main"> | |
| <div class="summary-label">TRIP SUMMARY</div> | |
| <div class="summary-loc">๐ {clean_loc}</div> | |
| <div class="summary-date">๐ {date}</div> | |
| </div> | |
| <div class="summary-metrics"> | |
| <div class="metric-box"> | |
| <span class="m-val">{total_tasks}</span> | |
| <span class="m-label">Tasks</span> | |
| </div> | |
| <div class="metric-box"> | |
| <span class="m-val">{total_time}<small>mins</small></span> | |
| <span class="m-label">Duration</span> | |
| </div> | |
| <div class="metric-box alert"> | |
| <span class="m-val">{high_priority}</span> | |
| <span class="m-label">High Prio</span> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| 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""" | |
| <div class="task-card-modern border-{p_cls}"> | |
| <div class="tc-header"> | |
| <span class="tc-title">{icon} {task_title}</span> | |
| <span class="tc-badge badge-{p_cls}">{priority}</span> | |
| </div> | |
| <div class="tc-body"> | |
| <div class="tc-row">๐ {location}</div> | |
| <div class="tc-row"> | |
| <span>๐ {display_time}</span> | |
| <span style="color: #cbd5e1; margin: 0 6px;">|</span> | |
| <span>โณ {duration}</span> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| # ๐ฅ๐ฅ๐ฅ Updated Timeline Function | |
| def create_timeline_html_enhanced(timeline): | |
| if not timeline: | |
| return """ | |
| <div style="text-align: center; padding: 20px; color: #94a3b8;"> | |
| No timeline data available yet. | |
| </div> | |
| """ | |
| html = '<div class="timeline-container">' | |
| 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'<div class="timeline-meta">๐ค๏ธ {weather_str}</div>' | |
| html += f""" | |
| <div class="timeline-stop"> | |
| <div class="timeline-left"> | |
| <div class="timeline-marker"></div> | |
| </div> | |
| <div class="timeline-card"> | |
| <div class="timeline-header"> | |
| <div class="timeline-location">{location}</div> | |
| <div class="timeline-time-badge">๐ {time_str}</div> | |
| </div> | |
| {weather_html} | |
| </div> | |
| </div> | |
| """ | |
| html += '</div>' | |
| 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 "" |