File size: 7,052 Bytes
1366db9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# bot_runner_helpers.py
from typing import Any, Dict, Optional

from bot_constants import (
    DEFAULT_CALLTRANSFER_MODE,
    DEFAULT_DIALIN_EXAMPLE,
    DEFAULT_SPEAK_SUMMARY,
    DEFAULT_STORE_SUMMARY,
    DEFAULT_TEST_IN_PREBUILT,
)
from call_connection_manager import CallConfigManager

# ----------------- Configuration Helpers ----------------- #


def determine_room_capabilities(config_body: Optional[Dict[str, Any]] = None) -> Dict[str, bool]:
    """Determine room capabilities based on the configuration.

    This function examines the configuration to determine which capabilities
    the Daily room should have enabled.

    Args:
        config_body: Configuration dictionary that determines room capabilities

    Returns:
        Dictionary of capability flags
    """
    capabilities = {
        "enable_dialin": False,
        "enable_dialout": False,
        # Add more capabilities here in the future as needed
    }

    if not config_body:
        return capabilities

    # Check for dialin capability
    capabilities["enable_dialin"] = "dialin_settings" in config_body

    # Check for dialout capability - needed for outbound calls or transfers
    has_dialout_settings = "dialout_settings" in config_body

    # Check if there's a transfer to an operator configured
    has_call_transfer = "call_transfer" in config_body

    # Enable dialout if any condition requires it
    capabilities["enable_dialout"] = has_dialout_settings or has_call_transfer

    return capabilities


def ensure_dialout_settings_array(body: Dict[str, Any]) -> Dict[str, Any]:
    """Ensures dialout_settings is an array of objects.

    Args:
        body: The configuration dictionary

    Returns:
        Updated configuration with dialout_settings as an array
    """
    if "dialout_settings" in body:
        # Convert to array if it's not already one
        if not isinstance(body["dialout_settings"], list):
            body["dialout_settings"] = [body["dialout_settings"]]

    return body


def ensure_prompt_config(body: Dict[str, Any]) -> Dict[str, Any]:
    """Ensures the body has appropriate prompts settings, but doesn't add defaults.

    Only makes sure the prompt section exists, allowing the bot script to handle defaults.

    Args:
        body: The configuration dictionary

    Returns:
        Updated configuration with prompt settings section
    """
    if "prompts" not in body:
        body["prompts"] = []
    return body


def create_call_transfer_settings(body: Dict[str, Any]) -> Dict[str, Any]:
    """Create call transfer settings based on configuration and customer mapping.

    Args:
        body: The configuration dictionary

    Returns:
        Call transfer settings dictionary
    """
    # Default transfer settings
    transfer_settings = {
        "mode": DEFAULT_CALLTRANSFER_MODE,
        "speakSummary": DEFAULT_SPEAK_SUMMARY,
        "storeSummary": DEFAULT_STORE_SUMMARY,
        "testInPrebuilt": DEFAULT_TEST_IN_PREBUILT,
    }

    # If call_transfer already exists, merge the defaults with the existing settings
    # This ensures all required fields exist while preserving user-specified values
    if "call_transfer" in body:
        existing_settings = body["call_transfer"]
        # Update defaults with existing settings (existing values will override defaults)
        for key, value in existing_settings.items():
            transfer_settings[key] = value
    else:
        # No existing call_transfer - check if we have dialin settings for customer lookup
        if "dialin_settings" in body:
            # Create a temporary routing manager just for customer lookup
            call_config_manager = CallConfigManager(body)

            # Get caller info
            caller_info = call_config_manager.get_caller_info()
            from_number = caller_info.get("caller_number")

            if from_number:
                # Get customer name from phone number
                customer_name = call_config_manager.get_customer_name(from_number)

                # If we know the customer name, add it to the config for the bot to use
                if customer_name:
                    transfer_settings["customerName"] = customer_name

    return transfer_settings


def create_simple_dialin_settings(body: Dict[str, Any]) -> Dict[str, Any]:
    """Create simple dialin settings based on configuration.

    Args:
        body: The configuration dictionary

    Returns:
        Simple dialin settings dictionary
    """
    # Default simple dialin settings
    simple_dialin_settings = {
        "testInPrebuilt": DEFAULT_TEST_IN_PREBUILT,
    }

    # If simple_dialin already exists, merge the defaults with the existing settings
    if "simple_dialin" in body:
        existing_settings = body["simple_dialin"]
        # Update defaults with existing settings (existing values will override defaults)
        for key, value in existing_settings.items():
            simple_dialin_settings[key] = value

    return simple_dialin_settings


def create_simple_dialout_settings(body: Dict[str, Any]) -> Dict[str, Any]:
    """Create simple dialout settings based on configuration.

    Args:
        body: The configuration dictionary

    Returns:
        Simple dialout settings dictionary
    """
    # Default simple dialout settings
    simple_dialout_settings = {
        "testInPrebuilt": DEFAULT_TEST_IN_PREBUILT,
    }

    # If simple_dialout already exists, merge the defaults with the existing settings
    if "simple_dialout" in body:
        existing_settings = body["simple_dialout"]
        # Update defaults with existing settings (existing values will override defaults)
        for key, value in existing_settings.items():
            simple_dialout_settings[key] = value

    return simple_dialout_settings


async def process_dialin_request(data: Dict[str, Any]) -> Dict[str, Any]:
    """Process incoming dial-in request data to create a properly formatted body.

    Converts camelCase fields received from webhook to snake_case format
    for internal consistency across the codebase.

    Args:
        data: Raw dialin data from webhook

    Returns:
        Properly formatted configuration with snake_case keys
    """
    # Create base body with dialin settings
    body = {
        "dialin_settings": {
            "to": data.get("To", ""),
            "from": data.get("From", ""),
            "call_id": data.get("callId", data.get("CallSid", "")),  # Convert to snake_case
            "call_domain": data.get("callDomain", ""),  # Convert to snake_case
        }
    }

    # Use the global default to determine which example to run for dialin webhooks
    example = DEFAULT_DIALIN_EXAMPLE

    # Configure the bot based on the example
    if example == "call_transfer":
        # Create call transfer settings
        body["call_transfer"] = create_call_transfer_settings(body)
    elif example == "simple_dialin":
        # Create simple dialin settings
        body["simple_dialin"] = create_simple_dialin_settings(body)

    return body