Skip to main content
Glama
coldfire-x

Owner avatar beijing-car-quota-draw

celebration_generator.py17.6 kB
""" Celebration HTML generator for lottery winners. Generates beautiful HTML pages with splash effects and animations to celebrate users who have won the car quota lottery. """ import json import random from datetime import datetime from pathlib import Path from typing import Dict, List, Optional, Any class CelebrationGenerator: """Generates celebration HTML pages for lottery winners.""" def __init__(self): """Initialize the celebration generator.""" self.templates_dir = Path(__file__).parent / "templates" self.templates_dir.mkdir(exist_ok=True) def generate_celebration_page( self, winner_info: Dict[str, Any], lottery_results: List[Dict[str, Any]], save_path: Optional[Path] = None ) -> str: """ Generate a celebration HTML page for a lottery winner. Args: winner_info: Information about the winner (application code, name, etc.) lottery_results: List of lottery results for this winner save_path: Optional path to save the HTML file Returns: HTML content as string """ # Extract winner details application_code = winner_info.get("application_code", "") name = winner_info.get("name", "恭喜您") id_info = winner_info.get("id_info", "") # Determine lottery type and details lottery_type = self._determine_lottery_type(lottery_results) lottery_details = self._extract_lottery_details(lottery_results) # Generate HTML content html_content = self._create_html_template( application_code=application_code, name=name, id_info=id_info, lottery_type=lottery_type, lottery_details=lottery_details ) # Save to file if path provided if save_path: save_path.parent.mkdir(parents=True, exist_ok=True) with open(save_path, 'w', encoding='utf-8') as f: f.write(html_content) return html_content def _determine_lottery_type(self, lottery_results: List[Dict[str, Any]]) -> str: """Determine the type of lottery based on results.""" if not lottery_results: return "新能源小客车指标" # Check the source file or type to determine lottery category first_result = lottery_results[0] source_url = first_result.get("source_url", "").lower() if "家庭" in source_url or "family" in source_url.lower(): return "家庭新能源小客车指标" elif "单位" in source_url or "unit" in source_url.lower(): return "单位新能源小客车指标" else: return "个人新能源小客车指标" def _extract_lottery_details(self, lottery_results: List[Dict[str, Any]]) -> Dict[str, Any]: """Extract relevant details from lottery results.""" if not lottery_results: return {} latest_result = lottery_results[0] # Assume first is most recent return { "sequence_number": latest_result.get("sequence_number"), "waiting_time": latest_result.get("waiting_time"), "source_file": latest_result.get("source_file"), "download_time": latest_result.get("download_time"), "total_results": len(lottery_results) } def _create_html_template( self, application_code: str, name: str, id_info: str, lottery_type: str, lottery_details: Dict[str, Any] ) -> str: """Create the HTML template with celebration effects.""" # Generate random celebration messages celebration_messages = [ "🎉 恭喜您!中签了!🎉", "🚗 您的新能源车梦想成真了!🚗", "🌟 幸运降临!您获得了车牌指标!🌟", "🎊 太棒了!您在摇号中获胜!🎊", "✨ 好运连连!车牌指标属于您了!✨" ] main_message = random.choice(celebration_messages) # Format date current_date = datetime.now().strftime("%Y年%m月%d日") # Create sharing messages sharing_messages = [ f"我在北京新能源车摇号中中签了!申请编码:{application_code}", f"好消息!我获得了{lottery_type}!", f"经过漫长等待,终于中签了!{lottery_type}到手!", f"分享一个好消息:我的{lottery_type}申请成功了!" ] share_text = random.choice(sharing_messages) html_content = f""" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>🎉 中签庆祝 - {name}</title> <style> * {{ margin: 0; padding: 0; box-sizing: border-box; }} body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; overflow-x: hidden; position: relative; }} /* Celebration animations */ .firework {{ position: absolute; width: 6px; height: 6px; border-radius: 50%; animation: firework 2s ease-out infinite; }} @keyframes firework {{ 0% {{ opacity: 1; transform: scale(0) translateY(0); }} 50% {{ opacity: 1; transform: scale(1) translateY(-100px); }} 100% {{ opacity: 0; transform: scale(0) translateY(-200px); }} }} .confetti {{ position: absolute; width: 8px; height: 8px; background: #ff6b6b; animation: confetti 3s ease-in-out infinite; }} @keyframes confetti {{ 0% {{ transform: translateY(-100vh) rotate(0deg); opacity: 1; }} 100% {{ transform: translateY(100vh) rotate(720deg); opacity: 0; }} }} .sparkle {{ position: absolute; width: 4px; height: 4px; background: #ffd700; border-radius: 50%; animation: sparkle 1.5s ease-in-out infinite; }} @keyframes sparkle {{ 0%, 100% {{ opacity: 0; transform: scale(0); }} 50% {{ opacity: 1; transform: scale(1); }} }} /* Main content */ .container {{ max-width: 800px; margin: 0 auto; padding: 2rem; text-align: center; position: relative; z-index: 10; }} .celebration-card {{ background: rgba(255, 255, 255, 0.95); border-radius: 20px; padding: 3rem 2rem; margin: 2rem 0; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); backdrop-filter: blur(10px); animation: cardAppear 0.8s ease-out; }} @keyframes cardAppear {{ from {{ opacity: 0; transform: translateY(50px) scale(0.9); }} to {{ opacity: 1; transform: translateY(0) scale(1); }} }} .main-title {{ font-size: 2.5rem; color: #2c3e50; margin-bottom: 1rem; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); animation: pulse 2s ease-in-out infinite; }} @keyframes pulse {{ 0%, 100% {{ transform: scale(1); }} 50% {{ transform: scale(1.05); }} }} .lottery-type {{ font-size: 1.5rem; color: #8e44ad; margin-bottom: 2rem; font-weight: 600; }} .details-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin: 2rem 0; }} .detail-card {{ background: linear-gradient(135deg, #f8f9fa, #e9ecef); border-radius: 15px; padding: 1.5rem; border: 2px solid #dee2e6; transition: transform 0.3s ease; }} .detail-card:hover {{ transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); }} .detail-label {{ font-size: 0.9rem; color: #6c757d; margin-bottom: 0.5rem; font-weight: 500; }} .detail-value {{ font-size: 1.2rem; color: #2c3e50; font-weight: 600; }} .action-buttons {{ margin-top: 3rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }} .btn {{ padding: 12px 30px; border: none; border-radius: 25px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease; text-decoration: none; display: inline-block; }} .btn-primary {{ background: linear-gradient(135deg, #667eea, #764ba2); color: white; }} .btn-secondary {{ background: linear-gradient(135deg, #ffecd2, #fcb69f); color: #8e44ad; }} .btn:hover {{ transform: translateY(-2px); box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2); }} .footer {{ margin-top: 3rem; color: rgba(255, 255, 255, 0.8); font-size: 0.9rem; }} /* Responsive design */ @media (max-width: 600px) {{ .container {{ padding: 1rem; }} .main-title {{ font-size: 2rem; }} .details-grid {{ grid-template-columns: 1fr; }} .action-buttons {{ flex-direction: column; align-items: center; }} }} </style> </head> <body> <!-- Celebration effects --> <div id="celebration-effects"></div> <div class="container"> <div class="celebration-card"> <h1 class="main-title">{main_message}</h1> <div class="lottery-type">{lottery_type}</div> <div class="details-grid"> <div class="detail-card"> <div class="detail-label">申请编码</div> <div class="detail-value">{application_code}</div> </div> <div class="detail-card"> <div class="detail-label">中签日期</div> <div class="detail-value">{current_date}</div> </div> {f''' <div class="detail-card"> <div class="detail-label">序号</div> <div class="detail-value">{lottery_details.get("sequence_number", "N/A")}</div> </div> ''' if lottery_details.get("sequence_number") else ""} {f''' <div class="detail-card"> <div class="detail-label">排队时间</div> <div class="detail-value">{lottery_details.get("waiting_time", "N/A")[:10] if lottery_details.get("waiting_time") else "N/A"}</div> </div> ''' if lottery_details.get("waiting_time") else ""} </div> <div class="action-buttons"> <button class="btn btn-primary" onclick="shareNews()"> 📱 分享好消息 </button> <button class="btn btn-secondary" onclick="downloadPage()"> 💾 保存纪念页 </button> <button class="btn btn-secondary" onclick="printPage()"> 🖨️ 打印纪念 </button> </div> </div> <div class="footer"> <p>🎊 祝贺您获得北京新能源小客车指标!🎊</p> <p>请及时关注后续购车和上牌流程</p> </div> </div> <script> // Create celebration effects function createCelebrationEffects() {{ const effectsContainer = document.getElementById('celebration-effects'); // Create fireworks for (let i = 0; i < 20; i++) {{ const firework = document.createElement('div'); firework.className = 'firework'; firework.style.left = Math.random() * 100 + '%'; firework.style.background = `hsl(${{Math.random() * 360}}, 70%, 60%)`; firework.style.animationDelay = Math.random() * 2 + 's'; effectsContainer.appendChild(firework); }} // Create confetti for (let i = 0; i < 30; i++) {{ const confetti = document.createElement('div'); confetti.className = 'confetti'; confetti.style.left = Math.random() * 100 + '%'; confetti.style.background = `hsl(${{Math.random() * 360}}, 70%, 60%)`; confetti.style.animationDelay = Math.random() * 3 + 's'; confetti.style.animationDuration = (Math.random() * 2 + 2) + 's'; effectsContainer.appendChild(confetti); }} // Create sparkles for (let i = 0; i < 50; i++) {{ const sparkle = document.createElement('div'); sparkle.className = 'sparkle'; sparkle.style.left = Math.random() * 100 + '%'; sparkle.style.top = Math.random() * 100 + '%'; sparkle.style.animationDelay = Math.random() * 1.5 + 's'; effectsContainer.appendChild(sparkle); }} }} // Share functionality function shareNews() {{ const shareText = "{share_text}"; if (navigator.share) {{ navigator.share({{ title: '🎉 北京车牌中签啦!', text: shareText, url: window.location.href }}); }} else {{ // Fallback - copy to clipboard navigator.clipboard.writeText(shareText).then(() => {{ alert('好消息已复制到剪贴板!快去分享吧!'); }}); }} }} // Download page as image (simplified) function downloadPage() {{ window.print(); }} // Print page function printPage() {{ window.print(); }} // Add sound effect (optional) function playSuccessSound() {{ const audio = new Audio('data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwbCy3BxuPzgl0gGJPXy+iKUB8aN'); audio.play().catch(() => {{}}); // Ignore errors }} // Initialize effects when page loads document.addEventListener('DOMContentLoaded', function() {{ createCelebrationEffects(); playSuccessSound(); // Add additional effects after a delay setTimeout(() => {{ document.querySelector('.celebration-card').style.transform = 'scale(1.02)'; setTimeout(() => {{ document.querySelector('.celebration-card').style.transform = 'scale(1)'; }}, 200); }}, 1000); }}); </script> </body> </html> """ return html_content def create_sharing_links(self, winner_info: Dict[str, Any]) -> Dict[str, str]: """Create social media sharing links.""" application_code = winner_info.get("application_code", "") share_text = f"我在北京新能源车摇号中中签了!申请编码:{application_code}" return { "wechat": f"weixin://", # WeChat sharing requires special handling "weibo": f"https://service.weibo.com/share/share.php?title={share_text}", "qq": f"https://connect.qq.com/widget/shareqq/index.html?title={share_text}", "copy": share_text }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/coldfire-x/beijing-car-quota-draw-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server