OFPBadWord / src /ofp_client.py
BladeSzaSza's picture
initial commit
c30b695
"""
OFP Client
Handles sending and receiving Open Floor Protocol envelopes via HTTPS
"""
import requests
import logging
import json
from typing import Dict, Optional
from .models import Envelope, DialogEvent
logger = logging.getLogger(__name__)
class OFPClient:
"""Client for sending OFP envelopes to conveners and other assistants"""
def __init__(self, speaker_uri: str, service_url: str, manifest: Dict):
self.speaker_uri = speaker_uri
self.service_url = service_url
self.manifest = manifest
logger.info(f"OFP Client initialized for {speaker_uri}")
def send_envelope(self, recipient_url: str, envelope: Envelope, timeout: int = 10) -> bool:
"""Send OFP envelope to recipient via HTTPS POST"""
try:
payload = envelope.to_payload()
logger.debug(f"Sending envelope to {recipient_url}: {json.dumps(payload, indent=2)}")
response = requests.post(
recipient_url,
json=payload,
headers={
'Content-Type': 'application/json',
'User-Agent': 'OFP-BadWord-Sentinel/1.0'
},
timeout=timeout
)
response.raise_for_status()
logger.info(f"βœ“ Envelope sent successfully to {recipient_url}")
return True
except requests.exceptions.Timeout:
logger.error(f"βœ— Timeout sending envelope to {recipient_url}")
return False
except requests.exceptions.RequestException as e:
logger.error(f"βœ— Failed to send envelope to {recipient_url}: {e}")
return False
except Exception as e:
logger.error(f"βœ— Unexpected error sending envelope: {e}")
return False
def send_private_alert(
self,
convener_uri: str,
convener_url: str,
conversation_id: str,
alert_data: Dict
) -> bool:
"""Send private alert to convener about profanity detection"""
try:
# Create alert text as JSON
alert_text = json.dumps(alert_data, indent=2)
# Create dialog event for the alert
alert_event = DialogEvent.create_text_event(
speaker_uri=self.speaker_uri,
text=alert_text
)
# Create envelope with private utterance event
envelope = Envelope(
schema={"version": "1.0.0"},
conversation={"id": conversation_id},
sender={"speakerUri": self.speaker_uri},
events=[{
"eventType": "utterance",
"to": {
"speakerUri": convener_uri,
"private": True # CRITICAL: Only convener sees this
},
"parameters": {
"dialogEvent": alert_event.to_dict()
}
}]
)
logger.info(f"Sending private alert to convener: {convener_uri}")
return self.send_envelope(convener_url, envelope)
except Exception as e:
logger.error(f"Error creating private alert: {e}")
return False
def send_public_message(
self,
conversation_id: str,
recipient_url: str,
text: str
) -> bool:
"""Send public message to the floor (visible to all participants)"""
try:
dialog_event = DialogEvent.create_text_event(
speaker_uri=self.speaker_uri,
text=text
)
envelope = Envelope(
schema={"version": "1.0.0"},
conversation={"id": conversation_id},
sender={"speakerUri": self.speaker_uri},
events=[{
"eventType": "utterance",
"parameters": {
"dialogEvent": dialog_event.to_dict()
}
}]
)
return self.send_envelope(recipient_url, envelope)
except Exception as e:
logger.error(f"Error sending public message: {e}")
return False
def request_floor(
self,
conversation_id: str,
convener_url: str,
convener_uri: str
) -> bool:
"""Request speaking floor from convener"""
envelope = Envelope(
schema={"version": "1.0.0"},
conversation={"id": conversation_id},
sender={"speakerUri": self.speaker_uri},
events=[{
"eventType": "floorRequest",
"to": {
"speakerUri": convener_uri
}
}]
)
return self.send_envelope(convener_url, envelope)
def get_manifest(self) -> Dict:
"""Return assistant manifest"""
return self.manifest