File size: 4,935 Bytes
c30b695
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
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