import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.DEBUG) # Set to DEBUG for detailed output import gradio as gr from gradio_calendar import Calendar from gematria import calculate_gematria, strip_diacritics from datetime import datetime, timedelta import json import inflect # --- Helper Functions --- def calculate_gematria_sum(text): if text: text_gematria = calculate_gematria(strip_diacritics(text)) return text_gematria else: return None # Custom function to convert number to ordinal words def number_to_ordinal_word(number): ordinal_dict = { 1: "first", 2: "second", 3: "third", 4: "fourth", 5: "fifth", 6: "sixth", 7: "seventh", 8: "eighth", 9: "ninth", 10: "tenth", 11: "eleventh", 12: "twelfth", 13: "thirteenth", 14: "fourteenth", 15: "fifteenth", 16: "sixteenth", 17: "seventeenth", 18: "eighteenth", 19: "nineteenth", 20: "twentieth", 21: "twentyfirst", 22: "twentysecond", 23: "twentythird", 24: "twentyfourth", 25: "twentyfifth", 26: "twentysixth", 27: "twentyseventh", 28: "twentyeighth", 29: "twentyninth", 30: "thirtieth", 31: "thirtyfirst" } return ordinal_dict.get(number, "") def date_to_words(date_string): """Converts a date in YYYY-MM-DD format to English words.""" inf_engine = inflect.engine() date_obj = datetime.strptime(date_string, "%Y-%m-%d") year = date_obj.year if 1100 <= year <= 1999: year_words = f"{inf_engine.number_to_words(year // 100, andword='') } hundred" if year % 100 != 0: year_words += f" {inf_engine.number_to_words(year % 100, andword='')}" else: year_words = inf_engine.number_to_words(year, andword='') year_formatted = year_words.replace(',', '') month = date_obj.strftime("%B") day = date_obj.day day_ordinal = number_to_ordinal_word(day) output_text = f"{day_ordinal} {month} {year_formatted}" return output_text def perform_gematria_calculation_for_date_range(start_date, end_date): logger.debug(f"Calculating date gematria for range: {start_date} - {end_date}") results = {} delta = timedelta(days=1) current_date = start_date while current_date <= end_date: date_string = current_date.strftime("%Y-%m-%d") date_words = date_to_words(date_string) date_gematria = calculate_gematria_sum(date_words) results[date_string] = { "date_words": date_words, "date_gematria": date_gematria, } current_date += delta logger.debug(f"Finished calculating date gematria.") return results def find_matching_dates(date_gematrias, names, search_journal_sum): logger.debug(f"Searching for matches with journal sum: {search_journal_sum}") matching_dates = {} for name in names: name_gematria = calculate_gematria_sum(name) target_date_gematria = search_journal_sum - name_gematria if name_gematria is not None else None logger.debug(f"Name: {name}, Gematria: {name_gematria}, Target Date Gematria: {target_date_gematria}") if target_date_gematria is not None: for date_str, date_data in date_gematrias.items(): if date_data["date_gematria"] == target_date_gematria: if name not in matching_dates: matching_dates[name] = [] matching_dates[name].append(date_str) logger.debug(f"Matches for {name}: {matching_dates.get(name, [])}") return matching_dates def find_shared_journal_sums(date_gematrias, names): """Finds shared journal sums and formats output with names and dates together.""" logger.debug("Calculating shared journal sums...") shared_sums = {} name_gematrias = {name: calculate_gematria_sum(name) for name in names} for date_str, date_data in date_gematrias.items(): date_gematria = date_data["date_gematria"] for name, name_gematria in name_gematrias.items(): journal_sum = date_gematria + name_gematria if journal_sum not in shared_sums: shared_sums[journal_sum] = {} # Initialize as a dictionary if name not in shared_sums[journal_sum]: shared_sums[journal_sum][name] = [] # Initialize list for each name shared_sums[journal_sum][name].append(date_str) # Filter out sums not shared by at least two names and format output result = {} for journal_sum, data in shared_sums.items(): if len(data) >= 2: # Check if at least two names have this sum result[journal_sum] = {} for name, dates in data.items(): result[journal_sum][name] = dates logger.debug(f"Shared Journal Sums: {result}") return result # --- Main Gradio App --- with gr.Blocks() as app: with gr.Row(): start_date = Calendar(type="datetime", label="Start Date") end_date = Calendar(type="datetime", label="End Date") with gr.Row(): names_input = gr.Textbox(label="Names (one per line)", lines=5) search_sum = gr.Number(label="Search Journal Sum", precision=0) with gr.Row(): calculate_btn = gr.Button("Search Journal Sum") shared_sums_btn = gr.Button("Find Shared Journal Sums") # new button matching_dates_output = gr.JSON(label="Matching Dates") shared_sums_output = gr.JSON(label="Shared Journal Sums") calculate_btn.click( lambda start_date, end_date, names_input, search_sum: calculate_and_find(start_date, end_date, names_input, int(search_sum), find_shared = False), # find_shared as input inputs=[start_date, end_date, names_input, search_sum], outputs=[matching_dates_output, shared_sums_output] # shared_sums_output included for consistency, even if empty ) shared_sums_btn.click( lambda start_date, end_date, names_input: calculate_and_find(start_date, end_date, names_input, 0, find_shared = True), # find_shared as input, search_sum is not used here. inputs=[start_date, end_date, names_input], #search_sum is irrelevant here, can be omitted outputs=[matching_dates_output, shared_sums_output] ) def calculate_and_find(start_date, end_date, names_input, search_journal_sum, find_shared = False): # added find_shared parameter names = [n.strip() for n in names_input.split("\n") if n.strip()] date_gematrias = perform_gematria_calculation_for_date_range(start_date, end_date) if find_shared: shared_sums = find_shared_journal_sums(date_gematrias, names) return None, json.dumps(shared_sums, indent=4, ensure_ascii=False) # outputs for consistency with 3 outputs else: matching_dates = find_matching_dates(date_gematrias, names, int(search_journal_sum)) return json.dumps(matching_dates, indent=4, ensure_ascii=False), None # shared sums are None when this button is pressed if __name__ == "__main__": app.launch(share=False)