Spaces:
Sleeping
Sleeping
Download app.py from RozzaCreat/Shabbat: direct link, hf CLI and curl.
- Browser
- Download file 19.6 kB
-
https://huggingface.co/spaces/RozzaCreat/Shabbat/resolve/main/app.py
- Command line
-
hf download hf://spaces/RozzaCreat/Shabbat/app.py
-
curl -L -o app.py https://huggingface.co/spaces/RozzaCreat/Shabbat/resolve/main/app.py
19.6 kB
| import gradio as gr | |
| import requests | |
| import json | |
| import datetime | |
| import re | |
| from bs4 import BeautifulSoup | |
| from typing import Optional, Dict, Any | |
| from urllib.parse import quote, urljoin | |
| class ShabbatCandleLightingAgent: | |
| """ | |
| AI Agent for finding Shabbat candle lighting times worldwide using Chabad.org | |
| """ | |
| def __init__(self): | |
| self.base_url = "https://www.chabad.org" | |
| self.candle_lighting_url = "https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Accurate-Shabbat-Candle-Lighting-Times.htm" | |
| def search_city_on_chabad(self, city_name: str) -> Optional[str]: | |
| """ | |
| Search for a city on Chabad.org and get the specific URL for candle lighting times | |
| """ | |
| try: | |
| # Clean and format city name | |
| city_clean = city_name.strip() | |
| search_query = quote(city_clean) | |
| headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', | |
| 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', | |
| 'Accept-Language': 'en-US,en;q=0.5', | |
| 'Accept-Encoding': 'gzip, deflate', | |
| 'Connection': 'keep-alive', | |
| 'Upgrade-Insecure-Requests': '1' | |
| } | |
| # Try different search approaches for Chabad.org | |
| search_strategies = [ | |
| # Direct city page approach | |
| f"https://www.chabad.org/calendar/candlelighting_cdo/jewish/{search_query}.htm", | |
| # Search with city parameter | |
| f"https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Accurate-Shabbat-Candle-Lighting-Times.htm?city={search_query}", | |
| # Alternative format | |
| f"https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Candle-Lighting-Times-{search_query}.htm", | |
| # General search | |
| f"https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Accurate-Shabbat-Candle-Lighting-Times.htm" | |
| ] | |
| for url in search_strategies: | |
| try: | |
| response = requests.get(url, headers=headers, timeout=15) | |
| if response.status_code == 200: | |
| # Check if the response contains candle lighting information | |
| content_lower = response.text.lower() | |
| if any(keyword in content_lower for keyword in ['candle lighting', 'light candles', 'shabbat', 'friday']): | |
| return url | |
| except Exception as e: | |
| print(f"Failed to fetch {url}: {e}") | |
| continue | |
| # Try POST request to the main search page | |
| try: | |
| post_data = { | |
| 'city': city_clean, | |
| 'submit': 'Get Times' | |
| } | |
| response = requests.post(self.candle_lighting_url, data=post_data, headers=headers, timeout=15) | |
| if response.status_code == 200 and 'candle lighting' in response.text.lower(): | |
| return response.url | |
| except Exception as e: | |
| print(f"POST request failed: {e}") | |
| except Exception as e: | |
| print(f"City search error: {e}") | |
| return self.candle_lighting_url # Return main page as fallback | |
| def extract_candle_lighting_times(self, html_content: str, city_name: str) -> Dict[str, Any]: | |
| """ | |
| Extract candle lighting times from Chabad.org HTML content using multiple strategies | |
| """ | |
| try: | |
| soup = BeautifulSoup(html_content, 'html.parser') | |
| text = soup.get_text().lower() | |
| # Multiple patterns to find candle lighting times | |
| candle_patterns = [ | |
| r'candle\s+lighting[:\s]*(\d{1,2}:\d{2}(?:\s*[ap]m)?)', | |
| r'light\s+candles[:\s]*(\d{1,2}:\d{2}(?:\s*[ap]m)?)', | |
| r'friday[:\s]*(\d{1,2}:\d{2}(?:\s*[ap]m)?)', | |
| r'(\d{1,2}:\d{2}\s*[ap]m?)(?=.*candle)', | |
| r'(\d{1,2}:\d{2}\s*[ap]m?)(?=.*light)', | |
| r'(\d{1,2}:\d{2}\s*[ap]m?)(?=.*friday)' | |
| ] | |
| # Patterns for Havdalah times | |
| havdalah_patterns = [ | |
| r'havdalah[:\s]*(\d{1,2}:\d{2}(?:\s*[ap]m)?)', | |
| r'saturday[:\s]*(\d{1,2}:\d{2}(?:\s*[ap]m)?)', | |
| r'(\d{1,2}:\d{2}\s*[ap]m?)(?=.*havdalah)', | |
| r'(\d{1,2}:\d{2}\s*[ap]m?)(?=.*saturday)' | |
| ] | |
| # Find candle lighting time | |
| candle_time = None | |
| for pattern in candle_patterns: | |
| match = re.search(pattern, text, re.IGNORECASE) | |
| if match: | |
| candle_time = match.group(1) | |
| break | |
| # Find Havdalah time | |
| havdalah_time = None | |
| for pattern in havdalah_patterns: | |
| match = re.search(pattern, text, re.IGNORECASE) | |
| if match: | |
| havdalah_time = match.group(1) | |
| break | |
| # Look for times in common HTML elements | |
| if not candle_time or not havdalah_time: | |
| # Check for time elements with specific classes or IDs | |
| time_selectors = [ | |
| '[class*="time"]', | |
| '[class*="candle"]', | |
| '[class*="light"]', | |
| '[id*="time"]', | |
| '[id*="candle"]', | |
| 'td', 'span', 'div' | |
| ] | |
| for selector in time_selectors: | |
| elements = soup.select(selector) | |
| for element in elements: | |
| element_text = element.get_text().strip() | |
| time_match = re.search(r'\d{1,2}:\d{2}(?:\s*[ap]m)?', element_text, re.IGNORECASE) | |
| if time_match: | |
| time_found = time_match.group() | |
| if not candle_time and any(word in element_text.lower() for word in ['candle', 'light', 'friday']): | |
| candle_time = time_found | |
| elif not havdalah_time and any(word in element_text.lower() for word in ['havdalah', 'saturday']): | |
| havdalah_time = time_found | |
| # Calculate current Shabbat dates | |
| now = datetime.datetime.now() | |
| days_until_friday = (4 - now.weekday()) % 7 | |
| if days_until_friday == 0 and now.hour >= 18: # If it's Friday evening, get next Friday | |
| days_until_friday = 7 | |
| friday = now + datetime.timedelta(days=days_until_friday) | |
| saturday = friday + datetime.timedelta(days=1) | |
| return { | |
| 'city': city_name, | |
| 'candle_lighting_time': candle_time, | |
| 'havdalah_time': havdalah_time, | |
| 'friday_date': friday.strftime('%B %d, %Y'), | |
| 'saturday_date': saturday.strftime('%B %d, %Y'), | |
| 'found_data': bool(candle_time or havdalah_time), | |
| 'search_successful': True | |
| } | |
| except Exception as e: | |
| print(f"Time extraction error: {e}") | |
| return { | |
| 'city': city_name, | |
| 'candle_lighting_time': None, | |
| 'havdalah_time': None, | |
| 'friday_date': None, | |
| 'saturday_date': None, | |
| 'found_data': False, | |
| 'search_successful': False, | |
| 'error': str(e) | |
| } | |
| def get_backup_times(self, city_name: str) -> Optional[Dict[str, Any]]: | |
| """ | |
| Try alternative sources for Shabbat times when Chabad.org fails | |
| """ | |
| try: | |
| # Alternative Jewish calendar websites | |
| backup_urls = [ | |
| f"https://www.hebcal.com/shabbat?city={quote(city_name)}", | |
| f"https://www.myzmanim.com/search.aspx?city={quote(city_name)}" | |
| ] | |
| headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' | |
| } | |
| for url in backup_urls: | |
| try: | |
| response = requests.get(url, headers=headers, timeout=10) | |
| if response.status_code == 200: | |
| times = self.extract_candle_lighting_times(response.text, city_name) | |
| if times.get('found_data'): | |
| times['source'] = 'backup' | |
| return times | |
| except Exception as e: | |
| print(f"Backup source {url} failed: {e}") | |
| continue | |
| except Exception as e: | |
| print(f"Backup sources error: {e}") | |
| return None | |
| def get_shabbat_times(self, city_input: str = "") -> str: | |
| """ | |
| Main function to get Shabbat candle lighting times | |
| """ | |
| try: | |
| city_name = city_input.strip() | |
| if not city_name: | |
| return self._format_error_response("❌ Please enter a city name to search for Shabbat times.") | |
| # Search Chabad.org for the city | |
| print(f"🔍 Searching for Shabbat times in: {city_name}") | |
| city_url = self.search_city_on_chabad(city_name) | |
| result_data = None | |
| source = "Chabad.org" | |
| if city_url: | |
| try: | |
| headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' | |
| } | |
| response = requests.get(city_url, headers=headers, timeout=15) | |
| if response.status_code == 200: | |
| result_data = self.extract_candle_lighting_times(response.text, city_name) | |
| print(f"📊 Extraction result: {result_data}") | |
| except Exception as e: | |
| print(f"❌ Chabad.org fetch error: {e}") | |
| # Try backup sources if Chabad.org didn't work well | |
| if not result_data or not result_data.get('found_data'): | |
| print("🔄 Trying backup sources...") | |
| backup_data = self.get_backup_times(city_name) | |
| if backup_data and backup_data.get('found_data'): | |
| result_data = backup_data | |
| source = "Alternative Jewish calendar source" | |
| # Format and return the response | |
| if result_data and result_data.get('found_data'): | |
| return self._format_success_response(result_data, source, city_url) | |
| else: | |
| return self._format_not_found_response(city_name, city_url) | |
| except Exception as e: | |
| print(f"Main function error: {e}") | |
| return self._format_error_response(f"❌ An error occurred: {str(e)}") | |
| def _format_success_response(self, data: Dict[str, Any], source: str, url: str = None) -> str: | |
| """Format successful response with Shabbat times""" | |
| candle_time = data.get('candle_lighting_time', 'Not found') | |
| havdalah_time = data.get('havdalah_time', 'Not found') | |
| response = f""" | |
| # 🕯️ Shabbat Candle Lighting Times | |
| ## 📍 Location: {data.get('city', 'Unknown')} | |
| ### 🕯️ **Candle Lighting (Friday)** | |
| **Time:** {candle_time} | |
| **Date:** {data.get('friday_date', 'This Friday')} | |
| ### ⭐ **Havdalah (Saturday)** | |
| **Time:** {havdalah_time} | |
| **Date:** {data.get('saturday_date', 'This Saturday')} | |
| --- | |
| ## 📋 **Important Notes:** | |
| - 🕯️ Light Shabbat candles **18 minutes before sunset** on Friday | |
| - ⭐ Havdalah is performed after **3 stars appear** on Saturday night | |
| - 🌍 Times are specific to your geographic location | |
| - ⏰ Always verify times with your local rabbi or Jewish community | |
| ## 📚 **Source Information:** | |
| **Data from:** {source} | |
| **Retrieved:** {datetime.datetime.now().strftime('%B %d, %Y at %I:%M %p')} | |
| {f"**URL:** {url}" if url else ""} | |
| --- | |
| ## 🙏 **Shabbat Shalom!** | |
| *May your Shabbat be filled with peace, joy, and spiritual connection.* | |
| **🔔 Reminder:** Set an alarm 30 minutes before candle lighting time to prepare properly. | |
| """ | |
| return response | |
| def _format_not_found_response(self, city_name: str, url: str = None) -> str: | |
| """Format response when times are not found""" | |
| return f""" | |
| # 🕯️ Shabbat Candle Lighting Times | |
| ## ❌ Times Not Found for {city_name} | |
| We searched multiple sources but couldn't find specific Shabbat candle lighting times for **{city_name}**. | |
| ### 🔍 **What you can try:** | |
| 1. **Check spelling** - Make sure the city name is spelled correctly | |
| 2. **Add country** - Try "City, Country" format (e.g., "Paris, France") | |
| 3. **Use major city** - Try the nearest major city instead | |
| 4. **Alternative spellings** - Try different variations of the city name | |
| ### 📍 **General Guidelines for {city_name}:** | |
| - 🕯️ **Candle lighting:** Typically 18 minutes before sunset on Friday | |
| - ⭐ **Havdalah:** Approximately 25-42 minutes after sunset on Saturday | |
| - 🌍 **Location matters:** Times vary significantly by geographic location | |
| ### 🌐 **Manual Resources:** | |
| - 📱 **Chabad.org:** [Direct search]({url or 'https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Accurate-Shabbat-Candle-Lighting-Times.htm'}) | |
| - 📱 **Hebcal.com:** Alternative Jewish calendar | |
| - 📞 **Local contacts:** Your synagogue or Chabad house | |
| ### 📞 **Local Resources:** | |
| - Contact your local Chabad house or synagogue | |
| - Check with your Jewish community center | |
| - Consult your rabbi for precise local customs | |
| --- | |
| **Retrieved:** {datetime.datetime.now().strftime('%B %d, %Y at %I:%M %p')} | |
| """ | |
| def _format_error_response(self, error_message: str) -> str: | |
| """Format error response""" | |
| return f""" | |
| # 🕯️ Shabbat Candle Lighting Times | |
| ## ⚠️ Error | |
| {error_message} | |
| ### 🔄 **Please try:** | |
| 1. **Refresh** and try again | |
| 2. **Check internet connection** | |
| 3. **Use a different city name** | |
| 4. **Visit Chabad.org directly:** [Candle Lighting Times](https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Accurate-Shabbat-Candle-Lighting-Times.htm) | |
| ### 📞 **Alternative:** | |
| Contact your local synagogue or Chabad house for accurate times. | |
| --- | |
| **Time:** {datetime.datetime.now().strftime('%B %d, %Y at %I:%M %p')} | |
| """ | |
| def create_shabbat_interface(): | |
| """Create the Gradio interface for the Shabbat Candle Lighting Agent""" | |
| agent = ShabbatCandleLightingAgent() | |
| with gr.Blocks(title="🕯️ Shabbat Candle Lighting Times", theme=gr.themes.Soft()) as app: | |
| gr.Markdown(""" | |
| # 🕯️ Shabbat Candle Lighting Times AI Agent | |
| **Get accurate Shabbat candle lighting and Havdalah times for any city worldwide** | |
| This AI agent searches Chabad.org and other reliable Jewish sources to find precise ritual times for your location. | |
| --- | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 📍 Location Input") | |
| city_input = gr.Textbox( | |
| label="🏙️ City Name", | |
| placeholder="Enter city name (e.g., 'New York', 'London, UK', 'Tel Aviv, Israel')", | |
| info="Please enter your city name to get accurate Shabbat times", | |
| lines=1 | |
| ) | |
| search_btn = gr.Button( | |
| "🔍 Get Shabbat Times", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| gr.Markdown(""" | |
| ### 💡 **City Input Tips:** | |
| - Use full city names for better results | |
| - Add country for common city names (e.g., "Paris, France") | |
| - Try nearest major city if yours isn't found | |
| - Use English city names for best search results | |
| """) | |
| with gr.Column(scale=2): | |
| output_area = gr.Markdown( | |
| label="📋 Shabbat Times Results", | |
| value=""" | |
| # 🕯️ Welcome! | |
| 👆 **Enter your city name above and click 'Get Shabbat Times'** | |
| --- | |
| **🕯️ Every Friday evening, Jewish families around the world light candles to welcome Shabbat** | |
| """ | |
| ) | |
| # Button click handlers | |
| search_btn.click( | |
| fn=agent.get_shabbat_times, | |
| inputs=[city_input], | |
| outputs=output_area | |
| ) | |
| # Resources and information | |
| with gr.Accordion("📚 Resources & Information", open=False): | |
| gr.Markdown(""" | |
| ### 🕯️ **About Shabbat Candle Lighting:** | |
| **Candle Lighting Time:** | |
| - Performed on Friday evening before sunset | |
| - Typically 18 minutes before sunset (varies by community) | |
| - Marks the beginning of Shabbat | |
| - Usually done by the woman of the house | |
| **Havdalah Time:** | |
| - Performed on Saturday evening after sunset | |
| - When three medium-sized stars are visible in the sky | |
| - Marks the end of Shabbat | |
| - Includes blessings over wine, spices, and candle | |
| ### 🌐 **Data Sources:** | |
| - **Primary:** [Chabad.org](https://www.chabad.org/calendar/candlelighting_cdo/aid/6226/jewish/Accurate-Shabbat-Candle-Lighting-Times.htm) | |
| - **Backup:** Hebcal.com and other Jewish calendar sites | |
| - **Method:** Intelligent web scraping with multiple fallback strategies | |
| ### ⚠️ **Important Disclaimers:** | |
| - Always consult your local rabbi for specific customs | |
| - Times may vary based on local Jewish community practices | |
| - This tool is for reference only - not a substitute for religious guidance | |
| - Some communities light candles at different intervals before sunset | |
| ### 🔧 **Technical Features:** | |
| - Multiple search strategies for maximum success on Chabad.org | |
| - Intelligent pattern matching to extract candle lighting times | |
| - Fallback to alternative Jewish calendar sources if needed | |
| - Manual city input for maximum accuracy and reliability | |
| """) | |
| gr.Markdown(""" | |
| --- | |
| **🙏 Shabbat Shalom!** | Built with ❤️ for the global Jewish community | |
| *For questions about Jewish law or local customs, please consult your rabbi or local Jewish community.* | |
| """) | |
| return app | |
| # Main execution | |
| if __name__ == "__main__": | |
| app = create_shabbat_interface() | |
| # Launch the application | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| debug=False, | |
| show_error=True | |
| ) |