Spaces:
Running
Running
| """ | |
| Price Inquiry Scenario Handler | |
| Helps users understand pricing and collects leads | |
| """ | |
| from typing import Dict, Any | |
| from .base_handler import BaseScenarioHandler | |
| class PriceInquiryHandler(BaseScenarioHandler): | |
| """ | |
| Handle price inquiry flow | |
| Steps: | |
| 1. Ask which event | |
| 2. Ask group size (1 person vs group) | |
| 3. Show pricing info | |
| 4. Ask if want PDF via email | |
| 5. Collect email → Send PDF | |
| 6. Ask if want SMS reminder | |
| 7-8. Collect phone → Send SMS | |
| """ | |
| def start(self, initial_data: Dict = None) -> Dict[str, Any]: | |
| """Start price inquiry flow""" | |
| return { | |
| "message": "Hello 👋 Bạn muốn xem giá vé của show nào?", | |
| "new_state": { | |
| "active_scenario": "price_inquiry", | |
| "scenario_step": 1, | |
| "scenario_data": initial_data or {} | |
| } | |
| } | |
| def next_step(self, current_step: int, user_input: str, scenario_data: Dict) -> Dict[str, Any]: | |
| """Process user input and advance scenario""" | |
| expected_type = self._get_expected_type(current_step) | |
| unexpected = self.handle_unexpected_input(user_input, expected_type, current_step) | |
| if unexpected: | |
| return unexpected | |
| # STEP 1: Which event? | |
| if current_step == 1: | |
| scenario_data['event_name'] = user_input | |
| return { | |
| "message": "Bạn đi 1 mình hay đi nhóm?", | |
| "new_state": { | |
| "active_scenario": "price_inquiry", | |
| "scenario_step": 2, | |
| "scenario_data": scenario_data | |
| }, | |
| "scenario_active": True | |
| } | |
| # STEP 2: Group size | |
| elif current_step == 2: | |
| group = self._detect_group_size(user_input) | |
| scenario_data['group_size'] = group | |
| event = scenario_data.get('event_name', 'event này') | |
| # Show pricing based on group size | |
| if group == 'single': | |
| msg = f"Giá vé cho **{event}**:\n- Vé thường: 300k\n- Vé VIP: 500k" | |
| else: | |
| msg = f"Giá vé nhóm cho **{event}**:\n- Nhóm 3-5: 250k/người\n- Nhóm 6+: 200k/người" | |
| return { | |
| "message": msg + "\n\nBạn muốn mình gửi bảng giá chi tiết qua email không?", | |
| "new_state": { | |
| "active_scenario": "price_inquiry", | |
| "scenario_step": 4, # Skip step 3 | |
| "scenario_data": scenario_data | |
| }, | |
| "scenario_active": True | |
| } | |
| # STEP 4: Want PDF? | |
| elif current_step == 4: | |
| choice = self._detect_yes_no(user_input) | |
| if choice == 'yes': | |
| return { | |
| "message": "Cho mình xin email để gửi PDF bảng giá nhé?", | |
| "new_state": { | |
| "active_scenario": "price_inquiry", | |
| "scenario_step": 5, | |
| "scenario_data": scenario_data | |
| }, | |
| "scenario_active": True | |
| } | |
| else: | |
| return { | |
| "message": "Okie! Bạn cần tư vấn gì thêm không? 😊", | |
| "new_state": None, | |
| "scenario_active": False, | |
| "end_scenario": True | |
| } | |
| # STEP 5: Collect email | |
| elif current_step == 5: | |
| email = user_input.strip() | |
| if not self._validate_email(email): | |
| return { | |
| "message": "Email này có vẻ không đúng. Bạn nhập lại giúp mình nhé?", | |
| "new_state": None, | |
| "scenario_active": True | |
| } | |
| scenario_data['email'] = email | |
| # Save lead | |
| try: | |
| self.lead_storage.save_lead( | |
| event_name=scenario_data.get('event_name'), | |
| email=email, | |
| interests={"group": scenario_data.get('group_size'), "wants_pdf": True}, | |
| session_id=scenario_data.get('session_id') | |
| ) | |
| print(f"📧 Lead saved: {email}") | |
| except Exception as e: | |
| print(f"⚠️ Error saving lead: {e}") | |
| return { | |
| "message": "Đã gửi PDF rồi nha 🎫\n\nBạn muốn nhận nhắc lịch qua SMS không?", | |
| "new_state": { | |
| "active_scenario": "price_inquiry", | |
| "scenario_step": 6, | |
| "scenario_data": scenario_data | |
| }, | |
| "scenario_active": True, | |
| "action": "send_pdf_email" | |
| } | |
| # STEP 6: Want SMS? | |
| elif current_step == 6: | |
| choice = self._detect_yes_no(user_input) | |
| if choice == 'yes': | |
| return { | |
| "message": "Cho mình xin số điện thoại để gửi SMS nhắc lịch nhé?", | |
| "new_state": { | |
| "active_scenario": "price_inquiry", | |
| "scenario_step": 8, | |
| "scenario_data": scenario_data | |
| }, | |
| "scenario_active": True | |
| } | |
| else: | |
| return { | |
| "message": "Okie! Cảm ơn bạn nha ✨", | |
| "new_state": None, | |
| "scenario_active": False, | |
| "end_scenario": True | |
| } | |
| # STEP 8: Collect phone | |
| elif current_step == 8: | |
| phone = user_input.strip() | |
| if not self._validate_phone(phone): | |
| return { | |
| "message": "Số điện thoại này có vẻ không đúng. Bạn nhập lại giúp mình nhé? (VD: 0901234567)", | |
| "new_state": None, | |
| "scenario_active": True | |
| } | |
| scenario_data['phone'] = phone | |
| # Save lead with phone | |
| try: | |
| self.lead_storage.save_lead( | |
| event_name=scenario_data.get('event_name'), | |
| email=scenario_data.get('email'), | |
| phone=phone, | |
| interests={"group": scenario_data.get('group_size'), "wants_reminder": True}, | |
| session_id=scenario_data.get('session_id') | |
| ) | |
| print(f"📱 Lead saved: {phone}") | |
| except Exception as e: | |
| print(f"⚠️ Error saving lead: {e}") | |
| return { | |
| "message": "Đã lưu rồi nha! Mình sẽ nhắc bạn trước show 1 ngày ✨", | |
| "new_state": None, | |
| "scenario_active": False, | |
| "end_scenario": True, | |
| "action": "save_lead_phone" | |
| } | |
| # Fallback | |
| return { | |
| "message": "Có lỗi xảy ra. Bạn muốn bắt đầu lại không?", | |
| "new_state": None, | |
| "scenario_active": False, | |
| "end_scenario": True | |
| } | |
| def _get_expected_type(self, step: int) -> str: | |
| """Get expected input type for each step""" | |
| type_map = { | |
| 1: 'event_name', | |
| 2: 'choice', | |
| 4: 'choice', | |
| 5: 'email', | |
| 6: 'choice', | |
| 8: 'phone' | |
| } | |
| return type_map.get(step, 'text') | |
| def _detect_group_size(self, user_input: str) -> str: | |
| """Detect if single or group""" | |
| input_lower = user_input.lower() | |
| if any(k in input_lower for k in ['nhóm', 'group', 'team', 'mấy người', 'nhiều']): | |
| return 'group' | |
| else: | |
| return 'single' | |
| def _detect_yes_no(self, user_input: str) -> str: | |
| """Detect yes/no""" | |
| input_lower = user_input.lower() | |
| return 'yes' if any(k in input_lower for k in ['có', 'yes', 'ok', 'được', 'ừ']) else 'no' | |