pgits Claude commited on
Commit
af2b4ec
Β·
1 Parent(s): be9ae65

Fix assistant: prefix removal in TTS by correcting regex patterns

Browse files

- Fixed regex from /^assistant:\\\\s*/i to /^assistant:\s*/i
- Removed double backslashes that prevented proper regex matching
- Now properly removes "assistant:" from TTS audio synthesis
- Tested locally and confirmed working correctly

πŸ€– Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

app/api/chat_widget.py CHANGED
@@ -1217,7 +1217,7 @@ async def chat_widget(request: Request):
1217
 
1218
  if (textContent && textContent.trim()) {
1219
  // Remove "assistant:" prefix if present
1220
- textContent = textContent.replace(/^assistant:\\\\s*/i, '').trim();
1221
 
1222
  // Start TTS synthesis immediately (non-blocking)
1223
  chatCalTTS.synthesizeAndPlay(textContent);
@@ -1298,7 +1298,7 @@ async def chat_widget(request: Request):
1298
 
1299
  // TTS integration - play the response (remove assistant prefix)
1300
  if (chatCalTTS && chatCalTTS.webrtcEnabled && data.response) {
1301
- let cleanResponse = data.response.replace(/^assistant:\\\\s*/i, '').trim();
1302
  chatCalTTS.synthesizeAndPlay(cleanResponse);
1303
  }
1304
  } else {
 
1217
 
1218
  if (textContent && textContent.trim()) {
1219
  // Remove "assistant:" prefix if present
1220
+ textContent = textContent.replace(/^assistant:\s*/i, '').trim();
1221
 
1222
  // Start TTS synthesis immediately (non-blocking)
1223
  chatCalTTS.synthesizeAndPlay(textContent);
 
1298
 
1299
  // TTS integration - play the response (remove assistant prefix)
1300
  if (chatCalTTS && chatCalTTS.webrtcEnabled && data.response) {
1301
+ let cleanResponse = data.response.replace(/^assistant:\s*/i, '').trim();
1302
  chatCalTTS.synthesizeAndPlay(cleanResponse);
1303
  }
1304
  } else {
chat_widget_detailed_20250920_200900.png DELETED
Binary file (56.4 kB)
 
interaction_test_20250920_200940.png DELETED
Binary file (54.6 kB)
 
main_chat_20250920_200900.png DELETED
Binary file (79.5 kB)
 
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
  [tool.poetry]
2
  name = "voicecal-ai"
3
- version = "1.0.22"
4
  description = "A friendly AI chatbot for booking Google Calendar appointments"
5
  authors = ["Peter <pgits.job@gmail.com>"]
6
 
 
1
  [tool.poetry]
2
  name = "voicecal-ai"
3
+ version = "1.0.23"
4
  description = "A friendly AI chatbot for booking Google Calendar appointments"
5
  authors = ["Peter <pgits.job@gmail.com>"]
6
 
screenshot_chat_widget_20250920_200832.png DELETED
Binary file (56.5 kB)
 
test_chat_widget.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Playwright test script to verify the chat widget at http://localhost:8000/chat-widget
4
+ Tests: page loading, JavaScript errors, CSS formatting, UI elements, chat functionality
5
+ """
6
+
7
+ import asyncio
8
+ import sys
9
+ from playwright.async_api import async_playwright
10
+ import json
11
+ from datetime import datetime
12
+
13
+ async def test_chat_widget():
14
+ """Comprehensive test of the chat widget interface"""
15
+
16
+ async with async_playwright() as p:
17
+ # Launch browser in headed mode so we can see what's happening
18
+ browser = await p.chromium.launch(headless=False, slow_mo=1000)
19
+ context = await browser.new_context(
20
+ viewport={'width': 1280, 'height': 720}
21
+ )
22
+
23
+ # Enable console logging to capture JavaScript errors
24
+ page = await context.new_page()
25
+ console_messages = []
26
+ errors = []
27
+
28
+ def handle_console(msg):
29
+ console_messages.append({
30
+ 'type': msg.type,
31
+ 'text': msg.text,
32
+ 'location': msg.location
33
+ })
34
+ print(f"Console {msg.type}: {msg.text}")
35
+
36
+ def handle_page_error(error):
37
+ errors.append(str(error))
38
+ print(f"Page Error: {error}")
39
+
40
+ def handle_response(response):
41
+ if response.status >= 400:
42
+ print(f"HTTP Error: {response.status} - {response.url}")
43
+
44
+ page.on('console', handle_console)
45
+ page.on('pageerror', handle_page_error)
46
+ page.on('response', handle_response)
47
+
48
+ try:
49
+ print("πŸš€ Starting chat widget test...")
50
+
51
+ # Test 1: Page Loading
52
+ print("\nπŸ“„ Test 1: Loading page at http://localhost:8000/chat-widget")
53
+
54
+ try:
55
+ response = await page.goto('http://localhost:8000/chat-widget', wait_until='networkidle')
56
+ print(f"βœ… Page loaded with status: {response.status}")
57
+
58
+ if response.status != 200:
59
+ print(f"❌ Unexpected status code: {response.status}")
60
+ return False
61
+
62
+ except Exception as e:
63
+ print(f"❌ Failed to load page: {e}")
64
+ return False
65
+
66
+ # Wait for page to fully load
67
+ await page.wait_for_load_state('domcontentloaded')
68
+ await asyncio.sleep(2) # Give time for any async loading
69
+
70
+ # Test 2: JavaScript Errors
71
+ print("\nπŸ› Test 2: Checking for JavaScript errors")
72
+ js_errors = [msg for msg in console_messages if msg['type'] == 'error']
73
+
74
+ # Filter out 404 errors that might be for optional resources
75
+ critical_js_errors = []
76
+ resource_404_errors = []
77
+
78
+ for error in js_errors:
79
+ if "Failed to load resource" in error['text'] and "404" in error['text']:
80
+ resource_404_errors.append(error)
81
+ else:
82
+ critical_js_errors.append(error)
83
+
84
+ if critical_js_errors:
85
+ print(f"❌ Found {len(critical_js_errors)} critical JavaScript errors:")
86
+ for error in critical_js_errors:
87
+ print(f" - {error['text']}")
88
+ return False
89
+ else:
90
+ print("βœ… No critical JavaScript errors found")
91
+
92
+ if resource_404_errors:
93
+ print(f"⚠️ Found {len(resource_404_errors)} resource 404 errors (may be non-critical):")
94
+ for error in resource_404_errors:
95
+ print(f" - {error['text']}")
96
+
97
+ if errors:
98
+ print(f"❌ Found {len(errors)} page errors:")
99
+ for error in errors:
100
+ print(f" - {error}")
101
+ return False
102
+ else:
103
+ print("βœ… No page errors found")
104
+
105
+ # Test 3: CSS and Layout Check
106
+ print("\n🎨 Test 3: Checking CSS formatting and layout")
107
+
108
+ # Check if main container exists and is visible
109
+ main_container = page.locator('#chat-widget, .chat-container, .chat-widget')
110
+ if await main_container.count() > 0:
111
+ print("βœ… Main chat container found")
112
+
113
+ # Check if container is visible
114
+ if await main_container.first.is_visible():
115
+ print("βœ… Main container is visible")
116
+ else:
117
+ print("❌ Main container is not visible")
118
+ return False
119
+ else:
120
+ print("❌ Main chat container not found")
121
+ return False
122
+
123
+ # Test 4: UI Elements Visibility and Positioning
124
+ print("\nπŸ” Test 4: Checking UI elements visibility and positioning")
125
+
126
+ # Check for common chat widget elements
127
+ elements_to_check = [
128
+ {'selector': 'input[type="text"], textarea, .message-input', 'name': 'Message input field'},
129
+ {'selector': 'button[type="submit"], .send-button, .submit-button', 'name': 'Send button'},
130
+ {'selector': '.chat-messages, .messages-container, .conversation', 'name': 'Messages container'},
131
+ ]
132
+
133
+ all_elements_found = True
134
+ for element in elements_to_check:
135
+ locator = page.locator(element['selector'])
136
+ count = await locator.count()
137
+ if count > 0:
138
+ is_visible = await locator.first.is_visible()
139
+ print(f"βœ… {element['name']}: Found ({count}) and {'visible' if is_visible else 'hidden'}")
140
+ if not is_visible:
141
+ all_elements_found = False
142
+ else:
143
+ print(f"❌ {element['name']}: Not found")
144
+ all_elements_found = False
145
+
146
+ if not all_elements_found:
147
+ print("⚠️ Some UI elements missing or hidden, but continuing with tests...")
148
+
149
+ # Test 5: Chat Interface Functionality
150
+ print("\nπŸ’¬ Test 5: Testing chat interface functionality")
151
+
152
+ # Try to find and interact with the input field
153
+ input_field = page.locator('input[type="text"], textarea, .message-input').first
154
+ send_button = page.locator('button[type="submit"], .send-button, .submit-button').first
155
+
156
+ if await input_field.count() > 0 and await send_button.count() > 0:
157
+ print("βœ… Found input field and send button")
158
+
159
+ try:
160
+ # Test typing in the input field
161
+ await input_field.fill("Hello, this is a test message")
162
+ print("βœ… Successfully typed in input field")
163
+
164
+ # Test clicking send button
165
+ await send_button.click()
166
+ print("βœ… Successfully clicked send button")
167
+
168
+ # Wait a moment for any response
169
+ await asyncio.sleep(3)
170
+
171
+ except Exception as e:
172
+ print(f"⚠️ Chat interaction failed: {e}")
173
+
174
+ else:
175
+ print("⚠️ Could not find input field or send button for interaction test")
176
+
177
+ # Test 6: Take Screenshot
178
+ print("\nπŸ“Έ Test 6: Taking screenshot for visual confirmation")
179
+
180
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
181
+ screenshot_path = f"/Users/petergits/dev/voiceCal-ai-v1/chat_widget_test_{timestamp}.png"
182
+
183
+ await page.screenshot(path=screenshot_path, full_page=True)
184
+ print(f"βœ… Screenshot saved to: {screenshot_path}")
185
+
186
+ # Additional checks for common CSS issues
187
+ print("\nπŸ”§ Additional CSS and Layout Checks:")
188
+
189
+ # Check page title
190
+ title = await page.title()
191
+ print(f"πŸ“„ Page title: {title}")
192
+
193
+ # Check body background and basic styling
194
+ body_styles = await page.evaluate("""
195
+ () => {
196
+ const body = document.body;
197
+ const computedStyles = window.getComputedStyle(body);
198
+ return {
199
+ backgroundColor: computedStyles.backgroundColor,
200
+ fontFamily: computedStyles.fontFamily,
201
+ margin: computedStyles.margin,
202
+ padding: computedStyles.padding
203
+ };
204
+ }
205
+ """)
206
+ print(f"🎨 Body styles: {json.dumps(body_styles, indent=2)}")
207
+
208
+ # Check if any CSS files failed to load
209
+ css_errors = [msg for msg in console_messages if 'css' in msg['text'].lower() or 'stylesheet' in msg['text'].lower()]
210
+ if css_errors:
211
+ print(f"⚠️ Found potential CSS loading issues:")
212
+ for error in css_errors:
213
+ print(f" - {error['text']}")
214
+ else:
215
+ print("βœ… No CSS loading errors detected")
216
+
217
+ print("\nπŸŽ‰ Test completed successfully!")
218
+ print(f"πŸ“Š Summary:")
219
+ print(f" - Console messages: {len(console_messages)}")
220
+ print(f" - JavaScript errors: {len(js_errors)}")
221
+ print(f" - Page errors: {len(errors)}")
222
+ print(f" - Screenshot saved: {screenshot_path}")
223
+
224
+ return True
225
+
226
+ except Exception as e:
227
+ print(f"❌ Test failed with exception: {e}")
228
+ return False
229
+
230
+ finally:
231
+ # Keep browser open for a moment to see the final state
232
+ print("\n⏳ Keeping browser open for 5 seconds for manual inspection...")
233
+ await asyncio.sleep(5)
234
+ await browser.close()
235
+
236
+ if __name__ == "__main__":
237
+ print("πŸ§ͺ Chat Widget Playwright Test")
238
+ print("=" * 50)
239
+
240
+ try:
241
+ result = asyncio.run(test_chat_widget())
242
+ if result:
243
+ print("\nβœ… All tests passed!")
244
+ sys.exit(0)
245
+ else:
246
+ print("\n❌ Some tests failed!")
247
+ sys.exit(1)
248
+ except KeyboardInterrupt:
249
+ print("\n⏹️ Test interrupted by user")
250
+ sys.exit(1)
251
+ except Exception as e:
252
+ print(f"\nπŸ’₯ Test crashed: {e}")
253
+ sys.exit(1)