LifeFlow-AI / ui /renderers.py
Marco310's picture
feat: improve UI/UX
ecbe9e4
# 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 ""