Skip to content

Commit c5fe156

Browse files
committed
Refactor labels to use "emoji swapping" utility
1 parent 1adfb24 commit c5fe156

File tree

8 files changed

+267
-77
lines changed

8 files changed

+267
-77
lines changed

coffee_ws/src/coffee_voice_agent_ui/coffee_voice_agent_ui/widgets/admin_override_widget.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
)
1414
from python_qt_binding.QtCore import Qt, pyqtSlot
1515
from python_qt_binding.QtGui import QFont
16+
from ..emoji_utils import format_title
1617

1718

1819
class AdminOverrideWidget(QWidget):
@@ -36,7 +37,7 @@ def _setup_ui(self):
3637
self.setLayout(layout)
3738

3839
# Title
39-
title = QLabel("⚙️ ADMIN OVERRIDE")
40+
title = QLabel(format_title('admin_override', 'ADMIN OVERRIDE'))
4041
title.setAlignment(Qt.AlignCenter)
4142
font = QFont()
4243
font.setBold(True)
@@ -62,7 +63,7 @@ def _create_status_section(self, parent_layout):
6263
status_frame.setLayout(status_layout)
6364

6465
# Header
65-
status_header = QLabel("📊 STATUS")
66+
status_header = QLabel(format_title('vip_status', 'STATUS'))
6667
status_header.setFont(QFont("Arial", 10, QFont.Bold))
6768
status_layout.addWidget(status_header)
6869

@@ -102,7 +103,7 @@ def _create_vip_history_section(self, parent_layout):
102103
history_frame.setLayout(history_layout)
103104

104105
# Header
105-
history_header = QLabel("📋 VIP HISTORY")
106+
history_header = QLabel(format_title('vip_history', 'VIP HISTORY'))
106107
history_header.setFont(QFont("Arial", 10, QFont.Bold))
107108
history_layout.addWidget(history_header)
108109

coffee_ws/src/coffee_voice_agent_ui/coffee_voice_agent_ui/widgets/agent_status_widget.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from python_qt_binding.QtGui import QFont, QPalette, QColor
1919

2020
from coffee_voice_agent_msgs.msg import AgentStatus
21+
from ..emoji_utils import format_title, get_connection_status
2122

2223

2324
class AgentStatusWidget(QWidget):
@@ -59,7 +60,7 @@ def _setup_ui(self):
5960
self.setLayout(layout)
6061

6162
# Title
62-
title = QLabel("🤖 AGENT STATUS")
63+
title = QLabel(format_title('agent_status', 'AGENT STATUS'))
6364
title.setAlignment(Qt.AlignCenter)
6465
font = QFont()
6566
font.setBold(True)
@@ -88,7 +89,7 @@ def _setup_ui(self):
8889
# Connection status
8990
conn_layout = QHBoxLayout()
9091
conn_layout.addWidget(QLabel("Connection:"))
91-
self.connection_label = QLabel("❌ Disconnected")
92+
self.connection_label = QLabel(get_connection_status(False))
9293
conn_layout.addWidget(self.connection_label)
9394
conn_layout.addStretch()
9495
status_layout.addLayout(conn_layout)
@@ -174,10 +175,10 @@ def update_connection(self, connected: bool):
174175
self.connection_status = connected
175176

176177
if connected:
177-
self.connection_label.setText("✅ Connected")
178+
self.connection_label.setText(get_connection_status(True))
178179
self.connection_label.setStyleSheet("color: green;")
179180
else:
180-
self.connection_label.setText("❌ Disconnected")
181+
self.connection_label.setText(get_connection_status(False))
181182
self.connection_label.setStyleSheet("color: red;")
182183

183184
def _update_dynamic_elements(self):
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Agent Status Widget SAFE VERSION - Displays agent overview information
4+
5+
SAFE VERSION: Uses QGridLayout instead of nested QHBoxLayout inside QVBoxLayout
6+
to avoid macOS Qt layout calculation crash in external terminals.
7+
8+
Shows the current agent state, connection status, conversation metrics,
9+
and general system health in a compact overview panel.
10+
"""
11+
12+
import time
13+
from datetime import datetime, timedelta
14+
from collections import deque
15+
16+
from python_qt_binding.QtWidgets import (
17+
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
18+
QFrame, QGridLayout, QProgressBar
19+
)
20+
from python_qt_binding.QtCore import Qt, QTimer
21+
from python_qt_binding.QtGui import QFont, QPalette, QColor
22+
23+
from coffee_voice_agent_msgs.msg import AgentStatus
24+
25+
26+
class AgentStatusWidgetSafe(QWidget):
27+
"""SAFE VERSION: Widget for displaying agent overview and status information
28+
29+
Uses QGridLayout instead of nested QHBoxLayouts to avoid macOS crash.
30+
"""
31+
32+
# State colors for visual indication
33+
STATE_COLORS = {
34+
'dormant': '#dc3545', # Red
35+
'connecting': '#ffc107', # Yellow
36+
'active': '#28a745', # Green
37+
'speaking': '#007bff', # Blue
38+
'disconnecting': '#6c757d' # Gray
39+
}
40+
41+
def __init__(self):
42+
super().__init__()
43+
self.setFixedSize(350, 250)
44+
45+
# Data tracking
46+
self.current_status = None
47+
self.connection_status = False
48+
self.session_start_time = None
49+
self.conversation_count = 0
50+
self.uptime_start = datetime.now()
51+
52+
# Status history for analytics
53+
self.status_history = deque(maxlen=100)
54+
55+
self._setup_ui()
56+
57+
# Update timer for dynamic elements
58+
self.update_timer = QTimer()
59+
self.update_timer.timeout.connect(self._update_dynamic_elements)
60+
self.update_timer.start(1000) # Update every second
61+
62+
def _setup_ui(self):
63+
"""Set up the widget UI using SAFE layout patterns"""
64+
layout = QVBoxLayout()
65+
self.setLayout(layout)
66+
67+
# Title
68+
title = QLabel("🤖 AGENT STATUS (SAFE)")
69+
title.setAlignment(Qt.AlignCenter)
70+
font = QFont()
71+
font.setBold(True)
72+
font.setPointSize(12)
73+
title.setFont(font)
74+
layout.addWidget(title)
75+
76+
# Status frame - KEEP this as it works fine
77+
self.status_frame = QFrame()
78+
self.status_frame.setFrameStyle(QFrame.Box)
79+
layout.addWidget(self.status_frame)
80+
81+
# SAFE CHANGE: Use QGridLayout instead of QVBoxLayout with nested QHBoxLayouts
82+
status_layout = QGridLayout()
83+
self.status_frame.setLayout(status_layout)
84+
85+
# Row 0: Current state display
86+
status_layout.addWidget(QLabel("State:"), 0, 0)
87+
self.state_label = QLabel("UNKNOWN")
88+
self.state_label.setAlignment(Qt.AlignCenter)
89+
# SAFE CHANGE: Use QFont.setBold() instead of font-weight in stylesheet
90+
font = self.state_label.font()
91+
font.setBold(True)
92+
self.state_label.setFont(font)
93+
self.state_label.setStyleSheet("padding: 4px 8px; border-radius: 4px;") # No font-weight
94+
status_layout.addWidget(self.state_label, 0, 1)
95+
96+
# Row 1: Connection status
97+
status_layout.addWidget(QLabel("Connection:"), 1, 0)
98+
self.connection_label = QLabel("❌ Disconnected")
99+
status_layout.addWidget(self.connection_label, 1, 1)
100+
101+
# Row 2: Session info
102+
status_layout.addWidget(QLabel("Session:"), 2, 0)
103+
self.session_label = QLabel("No active session")
104+
status_layout.addWidget(self.session_label, 2, 1)
105+
106+
# Row 3: Uptime
107+
status_layout.addWidget(QLabel("Uptime:"), 3, 0)
108+
self.uptime_label = QLabel("00:00:00")
109+
status_layout.addWidget(self.uptime_label, 3, 1)
110+
111+
# Row 4: Separator - span across both columns
112+
separator = QFrame()
113+
separator.setFrameShape(QFrame.HLine)
114+
separator.setFrameShadow(QFrame.Sunken)
115+
status_layout.addWidget(separator, 4, 0, 1, 2) # span 2 columns
116+
117+
# Row 5-7: Additional info - continue with grid layout
118+
status_layout.addWidget(QLabel("Phase:"), 5, 0)
119+
self.phase_label = QLabel("-")
120+
status_layout.addWidget(self.phase_label, 5, 1)
121+
122+
status_layout.addWidget(QLabel("Last Tool:"), 6, 0)
123+
self.tool_label = QLabel("-")
124+
status_layout.addWidget(self.tool_label, 6, 1)
125+
126+
status_layout.addWidget(QLabel("Conversations:"), 7, 0)
127+
self.conversation_count_label = QLabel("0")
128+
status_layout.addWidget(self.conversation_count_label, 7, 1)
129+
130+
def update_status(self, status: AgentStatus):
131+
"""Update the widget with new agent status"""
132+
self.current_status = status
133+
self.status_history.append((datetime.now(), status))
134+
135+
# Update state display with color coding
136+
state = status.behavioral_mode.upper()
137+
self.state_label.setText(state)
138+
139+
# Set state color - SAFE: Keep stylesheet simple, no font-weight
140+
color = self.STATE_COLORS.get(status.behavioral_mode, '#6c757d')
141+
self.state_label.setStyleSheet(f"""
142+
padding: 4px 8px;
143+
border-radius: 4px;
144+
background-color: {color};
145+
color: white;
146+
""")
147+
148+
# Update conversation phase
149+
phase = status.conversation_phase if status.conversation_phase else "idle"
150+
self.phase_label.setText(phase.title())
151+
152+
# Update last tool used
153+
tool = status.last_tool_used if status.last_tool_used else "none"
154+
self.tool_label.setText(tool)
155+
156+
# Track session changes
157+
if status.behavioral_mode in ['active', 'speaking']:
158+
if self.session_start_time is None:
159+
self.session_start_time = datetime.now()
160+
self.conversation_count += 1
161+
self.conversation_count_label.setText(str(self.conversation_count))
162+
elif status.behavioral_mode == 'dormant':
163+
if self.session_start_time is not None:
164+
self.session_start_time = None
165+
166+
def update_connection(self, connected: bool):
167+
"""Update connection status"""
168+
self.connection_status = connected
169+
170+
if connected:
171+
self.connection_label.setText("✅ Connected")
172+
self.connection_label.setStyleSheet("color: green;")
173+
else:
174+
self.connection_label.setText("❌ Disconnected")
175+
self.connection_label.setStyleSheet("color: red;")
176+
177+
def _update_dynamic_elements(self):
178+
"""Update time-based elements"""
179+
# Update uptime
180+
uptime = datetime.now() - self.uptime_start
181+
uptime_str = str(uptime).split('.')[0] # Remove microseconds
182+
self.uptime_label.setText(uptime_str)
183+
184+
# Update session duration
185+
if self.session_start_time:
186+
session_duration = datetime.now() - self.session_start_time
187+
session_str = str(session_duration).split('.')[0]
188+
self.session_label.setText(f"Active: {session_str}")
189+
else:
190+
self.session_label.setText("No active session")
191+
192+
def get_analytics_data(self):
193+
"""Get analytics data for the analytics widget"""
194+
return {
195+
'uptime': datetime.now() - self.uptime_start,
196+
'conversation_count': self.conversation_count,
197+
'current_state': self.current_status.behavioral_mode if self.current_status else 'unknown',
198+
'connection_status': self.connection_status,
199+
'status_history': list(self.status_history),
200+
'session_active': self.session_start_time is not None
201+
}

coffee_ws/src/coffee_voice_agent_ui/coffee_voice_agent_ui/widgets/analytics_widget.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
)
5959
from python_qt_binding.QtCore import Qt
6060
from python_qt_binding.QtGui import QFont, QPainter, QColor, QPen
61+
from ..emoji_utils import format_title
6162

6263

6364
class AnalyticsWidget(QWidget):
@@ -119,7 +120,7 @@ def _setup_ui(self):
119120
scroll_widget.setLayout(layout)
120121

121122
# Title
122-
title = QLabel("📊 ANALYTICS")
123+
title = QLabel(format_title('analytics', 'ANALYTICS'))
123124
title.setAlignment(Qt.AlignCenter)
124125
font = QFont()
125126
font.setBold(True)
@@ -152,7 +153,7 @@ def _create_session_performance_section(self, parent_layout):
152153
perf_frame.setLayout(perf_layout)
153154

154155
# Header
155-
perf_header = QLabel("📈 SESSION PERFORMANCE")
156+
perf_header = QLabel(format_title('session_performance', 'SESSION PERFORMANCE'))
156157
perf_header.setFont(QFont("Arial", 10, QFont.Bold))
157158
perf_layout.addWidget(perf_header)
158159

@@ -197,7 +198,7 @@ def _create_popular_interactions_section(self, parent_layout):
197198
interactions_frame.setLayout(interactions_layout)
198199

199200
# Header
200-
interactions_header = QLabel("🎯 POPULAR INTERACTIONS")
201+
interactions_header = QLabel(format_title('popular_interactions', 'POPULAR INTERACTIONS'))
201202
interactions_header.setFont(QFont("Arial", 10, QFont.Bold))
202203
interactions_layout.addWidget(interactions_header)
203204

@@ -218,7 +219,7 @@ def _create_emotion_trends_section(self, parent_layout):
218219
emotion_frame.setLayout(emotion_layout)
219220

220221
# Header
221-
emotion_header = QLabel("🎭 EMOTION TRENDS")
222+
emotion_header = QLabel(format_title('emotion_trends', 'EMOTION TRENDS'))
222223
emotion_header.setFont(QFont("Arial", 10, QFont.Bold))
223224
emotion_layout.addWidget(emotion_header)
224225

@@ -242,7 +243,7 @@ def _create_system_metrics_section(self, parent_layout):
242243
metrics_frame.setLayout(metrics_layout)
243244

244245
# Header
245-
metrics_header = QLabel("⚙️ SYSTEM METRICS")
246+
metrics_header = QLabel(format_title('system_metrics', 'SYSTEM METRICS'))
246247
metrics_header.setFont(QFont("Arial", 10, QFont.Bold))
247248
metrics_layout.addWidget(metrics_header)
248249

0 commit comments

Comments
 (0)