File size: 7,026 Bytes
769668f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88e0a0d
 
 
 
 
769668f
 
 
88e0a0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769668f
 
 
 
 
 
 
 
 
88e0a0d
769668f
 
 
88e0a0d
 
 
 
 
 
769668f
 
 
88e0a0d
769668f
88e0a0d
769668f
 
88e0a0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769668f
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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)