azettl commited on
Commit
dceb707
·
verified ·
1 Parent(s): 0e8f4af

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +238 -0
app.py CHANGED
@@ -293,6 +293,244 @@ class OpenFloorAgentServer:
293
  print(f"🚀 OpenFloor agent '{self.agent.manifest.identification.conversationalName}' started on port {self.port}")
294
  return True
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  def get_session_id(request: gr.Request = None) -> str:
297
  """Generate or retrieve session ID"""
298
  if request and hasattr(request, 'session_hash'):
 
293
  print(f"🚀 OpenFloor agent '{self.agent.manifest.identification.conversationalName}' started on port {self.port}")
294
  return True
295
 
296
+
297
+ class OpenFloorManager:
298
+ """Central floor manager for coordinating all OpenFloor agents"""
299
+
300
+ def __init__(self, port: int = 7860):
301
+ self.port = port
302
+ self.agent_registry = {} # speakerUri -> agent info
303
+ self.active_conversations = {} # conversation_id -> conversation state
304
+ self.visual_callback = None
305
+
306
+ def register_agent(self, manifest: Manifest, agent_url: str):
307
+ """Register an agent with the floor manager"""
308
+ speaker_uri = manifest.identification.speakerUri
309
+ self.agent_registry[speaker_uri] = {
310
+ 'manifest': manifest,
311
+ 'url': agent_url,
312
+ 'status': 'available',
313
+ 'last_seen': datetime.now()
314
+ }
315
+ print(f"🏛️ Floor Manager: Registered agent {manifest.identification.conversationalName}")
316
+
317
+ def discover_agents(self) -> List[Manifest]:
318
+ """Return manifests of all registered agents"""
319
+ return [info['manifest'] for info in self.agent_registry.values()]
320
+
321
+ def create_conversation(self, initial_participants: List[str] = None) -> str:
322
+ """Create a new conversation with optional initial participants"""
323
+ conversation_id = f"conv:{uuid.uuid4()}"
324
+
325
+ self.active_conversations[conversation_id] = {
326
+ 'id': conversation_id,
327
+ 'participants': initial_participants or [],
328
+ 'messages': [],
329
+ 'created_at': datetime.now(),
330
+ 'status': 'active'
331
+ }
332
+
333
+ print(f"🏛️ Floor Manager: Created conversation {conversation_id}")
334
+ return conversation_id
335
+
336
+ def invite_agent_to_conversation(self, conversation_id: str, target_speaker_uri: str,
337
+ inviting_speaker_uri: str) -> bool:
338
+ """Send InviteEvent to an agent"""
339
+ if conversation_id not in self.active_conversations:
340
+ return False
341
+
342
+ if target_speaker_uri not in self.agent_registry:
343
+ return False
344
+
345
+ conversation = self.active_conversations[conversation_id]
346
+ target_agent = self.agent_registry[target_speaker_uri]
347
+
348
+ # Create proper InviteEvent
349
+ invite_envelope = Envelope(
350
+ conversation=Conversation(id=conversation_id),
351
+ sender=Sender(speakerUri=inviting_speaker_uri),
352
+ events=[
353
+ InviteEvent(
354
+ to=To(speakerUri=target_speaker_uri),
355
+ parameters={
356
+ 'conversation_id': conversation_id,
357
+ 'invited_by': inviting_speaker_uri,
358
+ 'invitation_message': f"You are invited to join the expert analysis discussion"
359
+ }
360
+ )
361
+ ]
362
+ )
363
+
364
+ # Send invitation to target agent
365
+ response = self._send_to_agent(target_agent['url'], invite_envelope)
366
+
367
+ if response:
368
+ # Add to conversation participants
369
+ if target_speaker_uri not in conversation['participants']:
370
+ conversation['participants'].append(target_speaker_uri)
371
+ self._update_visual_state(conversation_id)
372
+ return True
373
+
374
+ return False
375
+
376
+ def route_message(self, envelope: Envelope) -> bool:
377
+ """Route message to appropriate recipients"""
378
+ conversation_id = envelope.conversation.id
379
+
380
+ if conversation_id not in self.active_conversations:
381
+ return False
382
+
383
+ conversation = self.active_conversations[conversation_id]
384
+
385
+ # Process each event in the envelope
386
+ for event in envelope.events:
387
+ if hasattr(event, 'to') and event.to:
388
+ # Directed message - send to specific agent
389
+ target_uri = event.to.speakerUri
390
+ if target_uri in self.agent_registry:
391
+ target_agent = self.agent_registry[target_uri]
392
+ self._send_to_agent(target_agent['url'], envelope)
393
+ else:
394
+ # Broadcast to all conversation participants
395
+ for participant_uri in conversation['participants']:
396
+ if participant_uri != envelope.sender.speakerUri: # Don't echo back
397
+ if participant_uri in self.agent_registry:
398
+ participant_agent = self.agent_registry[participant_uri]
399
+ self._send_to_agent(participant_agent['url'], envelope)
400
+
401
+ # Store message in conversation history
402
+ conversation['messages'].append({
403
+ 'envelope': envelope,
404
+ 'timestamp': datetime.now()
405
+ })
406
+
407
+ self._update_visual_state(conversation_id)
408
+ return True
409
+
410
+ def _send_to_agent(self, agent_url: str, envelope: Envelope) -> bool:
411
+ """Send envelope to specific agent"""
412
+ try:
413
+ response = requests.post(
414
+ f"{agent_url}/openfloor/conversation",
415
+ json=json.loads(envelope.to_json()),
416
+ headers={'Content-Type': 'application/json'},
417
+ timeout=30
418
+ )
419
+ return response.status_code == 200
420
+ except Exception as e:
421
+ print(f"🏛️ Floor Manager: Error sending to {agent_url}: {e}")
422
+ return False
423
+
424
+ def _update_visual_state(self, conversation_id: str):
425
+ """Update visual interface based on conversation state"""
426
+ if self.visual_callback and conversation_id in self.active_conversations:
427
+ conversation = self.active_conversations[conversation_id]
428
+
429
+ # Convert to visual format
430
+ participants = []
431
+ messages = []
432
+
433
+ for participant_uri in conversation['participants']:
434
+ if participant_uri in self.agent_registry:
435
+ agent_info = self.agent_registry[participant_uri]
436
+ participants.append(agent_info['manifest'].identification.conversationalName)
437
+
438
+ for msg_info in conversation['messages']:
439
+ envelope = msg_info['envelope']
440
+ sender_uri = envelope.sender.speakerUri
441
+
442
+ if sender_uri in self.agent_registry:
443
+ sender_name = self.agent_registry[sender_uri]['manifest'].identification.conversationalName
444
+
445
+ # Extract message content
446
+ for event in envelope.events:
447
+ if hasattr(event, 'eventType') and event.eventType == 'utterance':
448
+ # Extract text from dialog event
449
+ dialog_event = event.parameters.get('dialogEvent')
450
+ if dialog_event:
451
+ features = dialog_event.get('features', {})
452
+ text_feature = features.get('text', {})
453
+ tokens = text_feature.get('tokens', [])
454
+ text = ' '.join([token.get('value', '') for token in tokens])
455
+
456
+ messages.append({
457
+ 'speaker': sender_name,
458
+ 'text': text,
459
+ 'timestamp': msg_info['timestamp'].strftime('%H:%M:%S')
460
+ })
461
+
462
+ self.visual_callback({
463
+ 'participants': participants,
464
+ 'messages': messages,
465
+ 'currentSpeaker': None,
466
+ 'thinking': [],
467
+ 'showBubbles': participants,
468
+ 'avatarImages': avatar_images
469
+ })
470
+
471
+ def set_visual_callback(self, callback):
472
+ """Set callback for visual updates"""
473
+ self.visual_callback = callback
474
+
475
+ def start_floor_manager_service(self):
476
+ """Start the floor manager HTTP service"""
477
+ from flask import Flask, request, jsonify
478
+
479
+ app = Flask("openfloor-manager")
480
+
481
+ @app.route('/openfloor/discover', methods=['GET'])
482
+ def discover_agents():
483
+ """Return list of available agent manifests"""
484
+ manifests = [json.loads(manifest.to_json()) for manifest in self.discover_agents()]
485
+ return jsonify(manifests)
486
+
487
+ @app.route('/openfloor/conversation', methods=['POST'])
488
+ def handle_conversation():
489
+ """Handle incoming conversation messages"""
490
+ try:
491
+ envelope_data = request.get_json()
492
+ envelope = Envelope.from_json(json.dumps(envelope_data))
493
+
494
+ success = self.route_message(envelope)
495
+
496
+ if success:
497
+ return jsonify({'status': 'routed'})
498
+ else:
499
+ return jsonify({'error': 'Failed to route message'}), 400
500
+
501
+ except Exception as e:
502
+ return jsonify({'error': str(e)}), 500
503
+
504
+ @app.route('/openfloor/invite', methods=['POST'])
505
+ def invite_agent():
506
+ """Handle agent invitation requests"""
507
+ try:
508
+ data = request.get_json()
509
+ conversation_id = data['conversation_id']
510
+ target_speaker_uri = data['target_speaker_uri']
511
+ inviting_speaker_uri = data['inviting_speaker_uri']
512
+
513
+ success = self.invite_agent_to_conversation(
514
+ conversation_id, target_speaker_uri, inviting_speaker_uri
515
+ )
516
+
517
+ return jsonify({'success': success})
518
+
519
+ except Exception as e:
520
+ return jsonify({'error': str(e)}), 500
521
+
522
+ # Start server in background thread
523
+ import threading
524
+ server_thread = threading.Thread(
525
+ target=lambda: app.run(host='localhost', port=self.port + 100, debug=False)
526
+ )
527
+ server_thread.daemon = True
528
+ server_thread.start()
529
+
530
+ print(f"🏛️ OpenFloor Manager started on port {self.port + 100}")
531
+ return True
532
+
533
+
534
  def get_session_id(request: gr.Request = None) -> str:
535
  """Generate or retrieve session ID"""
536
  if request and hasattr(request, 'session_hash'):