from datetime import datetime, timezone from urllib.parse import urlparse def normalize_url(url: str | None) -> str | None: """Normalize user-provided URL to include scheme and validate basic structure.""" if not url: return None url = url.strip() if not url: return None if not url.startswith(("http://", "https://")): url = "https://" + url # add https if missing # quick parse check parsed = urlparse(url) if not parsed.netloc: return None # invalid URL return url def extract_tally_payload(payload: dict): """ Extracts key chatbot information from a Tally webhook payload. Handles optional/missing multi-select and dropdown values. """ fields = payload.get("data", {}).get("fields", []) # Map key -> field key_map = {f["key"]: f for f in fields} # Submission ID submission_id = payload.get("data", {}).get("submissionId") pricing_plan = key_map.get("question_K6rZP8_15f06788-71a0-4a4a-903e-68944b6cb967", {}).get("value") or None # Company info company_name = key_map.get("question_kyp5Dd", {}).get("value") chatbot_name = key_map.get("question_vAp47X", {}).get("value") or f"{company_name} Assistant" raw_url = key_map.get("question_K6gL7z", {}).get("value") website_url = normalize_url(raw_url) # Multi-select chatbot purpose purpose_field = key_map.get("question_1lxMZ4", {}) option_map = {opt["id"]: opt["text"] for opt in purpose_field.get("options", [])} value_ids = purpose_field.get("value") or [] chatbot_purpose = [option_map.get(v, v) for v in value_ids] # Multi-select additional content content_field = key_map.get("question_MbgLkE", {}) content_option_map = {opt["id"]: opt["text"] for opt in content_field.get("options", [])} value_ids = content_field.get("value") or [] additional_content = [content_option_map.get(v, v) for v in value_ids] # Sensitive topics sensitive_topics = key_map.get("question_J6gLaz", {}).get("value") or None # Tone/style dropdown tone_field = key_map.get("question_N694OQ", {}) tone_option_map = {opt["id"]: opt["text"] for opt in tone_field.get("options", [])} value_ids = tone_field.get("value") or [] tone_style = [tone_option_map.get(v, v) for v in value_ids] if value_ids else None # Contact contact_email = key_map.get("question_qd7YN7", {}).get("value") contact_phone = key_map.get("question_QDaxEp", {}).get("value") # Timestamps submitted_at_str = payload.get("data", {}).get("createdAt") submitted_at = datetime.fromisoformat(submitted_at_str.replace("Z", "+00:00")) return { "submission_id": submission_id, "company_name": company_name, "chatbot_name": chatbot_name, "pricing_plan": pricing_plan, "website_url": website_url, "chatbot_purpose": chatbot_purpose, "additional_content": additional_content, "sensitive_topics": sensitive_topics, "tone_style": tone_style, "contact_email": contact_email, "contact_phone": contact_phone, "submitted_at": submitted_at, }