ethiotech4848 commited on
Commit
08bb5ea
Β·
verified Β·
1 Parent(s): 5e79925

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -25
app.py CHANGED
@@ -225,39 +225,79 @@ async def get_chatwoot_conversation(conversation_id: int) -> Optional[dict]:
225
 
226
  msgs_resp.raise_for_status()
227
 
228
- # The API returns the payload with meta and messages
229
  response_data = msgs_resp.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
- # Extract messages from the response
232
- messages = response_data.get('payload', [])
233
  if not isinstance(messages, list):
234
- print(f"⚠️ Unexpected messages format. Expected list, got: {type(messages)}")
235
  return None
236
 
237
  print(f"\nπŸ“© Successfully parsed {len(messages)} messages")
238
  if messages:
239
- print(f"First message: {messages[0].get('content', 'No content')[:100]}...")
 
 
240
 
241
- # Filter out system messages and format for Slack
242
  filtered_messages = []
243
  for msg in messages:
244
- # Only include messages with content and from known senders
245
- if msg.get('content') and msg.get('sender') and msg.get('sender').get('type') in ['contact', 'user']:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  filtered_msg = {
247
  'id': msg.get('id'),
248
- 'content': msg.get('content'),
249
  'created_at': msg.get('created_at'),
250
  'sender': {
251
- 'type': msg.get('sender', {}).get('type'),
252
- 'name': msg.get('sender', {}).get('name', 'Unknown')
253
  },
254
- 'message_type': msg.get('message_type')
 
255
  }
256
  filtered_messages.append(filtered_msg)
 
 
 
 
 
 
 
 
 
257
 
258
- # Return the filtered messages with metadata
259
  return {
260
- 'meta': response_data.get('meta', {}),
261
  'payload': filtered_messages
262
  }
263
 
@@ -428,6 +468,7 @@ async def _process_slack_command(conversation_id: str, response_url: str):
428
  )
429
 
430
  async def send_chatwoot_message(conversation_id: str, content: str):
 
431
  message_payload = {
432
  "content": content,
433
  "message_type": "outgoing",
@@ -437,19 +478,53 @@ async def send_chatwoot_message(conversation_id: str, content: str):
437
  }
438
 
439
  try:
440
- async with httpx.AsyncClient() as http:
441
- url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
442
- print("πŸ“€ Sending to Chatwoot:", url)
443
- print("πŸ“¦ Payload:", json.dumps(message_payload, indent=2))
 
 
 
 
 
 
444
 
445
- resp = await http.get(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  url,
447
- headers={
448
- "Content-Type": "application/json",
449
- "api_access_token": CHATWOOT_API_KEY,
450
- },
451
- json=message_payload,
452
  )
453
- print("πŸ“¬ Chatwoot Response:", resp.status_code, resp.text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  except Exception as e:
455
  print("❌ Chatwoot Send Error:", e)
 
225
 
226
  msgs_resp.raise_for_status()
227
 
228
+ # Parse the JSON response
229
  response_data = msgs_resp.json()
230
+ print(f"πŸ“Š Response data type: {type(response_data).__name__}")
231
+
232
+ # Handle different response formats
233
+ if isinstance(response_data, dict):
234
+ # If the response has a 'payload' key, use that
235
+ messages = response_data.get('payload', [])
236
+ meta = response_data.get('meta', {})
237
+ elif isinstance(response_data, list):
238
+ # If the response is directly a list of messages
239
+ messages = response_data
240
+ meta = {}
241
+ else:
242
+ print(f"⚠️ Unexpected response format: {type(response_data)}")
243
+ return None
244
 
 
 
245
  if not isinstance(messages, list):
246
+ print(f"⚠️ Messages is not a list: {type(messages)}")
247
  return None
248
 
249
  print(f"\nπŸ“© Successfully parsed {len(messages)} messages")
250
  if messages:
251
+ first_msg = messages[0]
252
+ print(f"First message type: {type(first_msg).__name__}")
253
+ print(f"First message keys: {list(first_msg.keys()) if hasattr(first_msg, 'keys') else 'N/A'}")
254
 
255
+ # Process and filter messages
256
  filtered_messages = []
257
  for msg in messages:
258
+ try:
259
+ # Skip if no content or sender info
260
+ if not msg.get('content') or not isinstance(msg.get('content'), str):
261
+ continue
262
+
263
+ # Get sender info, handle different formats
264
+ sender = msg.get('sender', {})
265
+ sender_type = None
266
+ sender_name = 'Unknown'
267
+
268
+ if isinstance(sender, dict):
269
+ sender_type = sender.get('type')
270
+ sender_name = sender.get('name') or sender.get('available_name', 'Unknown')
271
+
272
+ # Only include relevant message types
273
+ if sender_type not in ['contact', 'user', 'agent']:
274
+ continue
275
+
276
+ # Create the filtered message
277
  filtered_msg = {
278
  'id': msg.get('id'),
279
+ 'content': msg['content'],
280
  'created_at': msg.get('created_at'),
281
  'sender': {
282
+ 'type': sender_type,
283
+ 'name': sender_name
284
  },
285
+ 'message_type': 'incoming' if msg.get('message_type') == 0 else 'outgoing',
286
+ 'timestamp': msg.get('created_at')
287
  }
288
  filtered_messages.append(filtered_msg)
289
+
290
+ except Exception as e:
291
+ print(f"⚠️ Error processing message {msg.get('id')}: {str(e)}")
292
+ continue
293
+
294
+ print(f"βœ… Filtered to {len(filtered_messages)} relevant messages")
295
+
296
+ # Sort messages by timestamp if available
297
+ filtered_messages.sort(key=lambda x: x.get('timestamp', 0))
298
 
 
299
  return {
300
+ 'meta': meta,
301
  'payload': filtered_messages
302
  }
303
 
 
468
  )
469
 
470
  async def send_chatwoot_message(conversation_id: str, content: str):
471
+ """Send a message to a Chatwoot conversation"""
472
  message_payload = {
473
  "content": content,
474
  "message_type": "outgoing",
 
478
  }
479
 
480
  try:
481
+ url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
482
+ headers = {
483
+ "Content-Type": "application/json",
484
+ "api_access_token": CHATWOOT_API_KEY,
485
+ }
486
+
487
+ print(f"πŸ“€ Sending to Chatwoot: {url}")
488
+ print(f"πŸ”‘ Using API key: {CHATWOOT_API_KEY[:5]}..." if CHATWOOT_API_KEY else "❌ No API key provided!")
489
+ print("πŸ“¦ Payload:", json.dumps(message_payload, indent=2))
490
+ print("πŸ”‘ Headers:", json.dumps({k: '***' if 'token' in k.lower() or 'key' in k.lower() else v for k, v in headers.items()}, indent=2))
491
 
492
+ async with httpx.AsyncClient() as http:
493
+ # First, try to get the conversation to verify access
494
+ conv_url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}"
495
+ print(f"πŸ” Checking conversation access: {conv_url}")
496
+
497
+ # Test GET request to verify conversation access
498
+ test_resp = await http.get(conv_url, headers=headers)
499
+ print(f"πŸ” Conversation check status: {test_resp.status_code}")
500
+ print(f"πŸ” Response: {test_resp.text[:500]}..." if test_resp.text else "No response body")
501
+
502
+ if test_resp.status_code != 200:
503
+ error_msg = f"Failed to access conversation: {test_resp.status_code} - {test_resp.text}"
504
+ print(f"❌ {error_msg}")
505
+ return {"status": "error", "message": error_msg}
506
+
507
+ # If we can access the conversation, try to send the message
508
+ print("βœ… Conversation access verified. Sending message...")
509
+ resp = await http.post(
510
  url,
511
+ headers=headers,
512
+ json=message_payload
 
 
 
513
  )
514
+ print(f"πŸ“¬ Chatwoot Response Status: {resp.status_code}")
515
+ print(f"πŸ“¬ Response Body: {resp.text}")
516
+
517
+ if resp.status_code != 200:
518
+ error_msg = f"Failed to send message: {resp.status_code} - {resp.text}"
519
+ print(f"❌ {error_msg}")
520
+ return {"status": "error", "message": error_msg}
521
+
522
+ return {"status": "success", "data": resp.json()}
523
+
524
+ except httpx.HTTPStatusError as e:
525
+ error_msg = f"HTTP error occurred: {str(e)}"
526
+ print(f"❌ {error_msg}")
527
+ print(f"Response: {e.response.text if hasattr(e, 'response') else 'No response'}")
528
+ return {"status": "error", "message": error_msg}
529
  except Exception as e:
530
  print("❌ Chatwoot Send Error:", e)