Spaces:
Sleeping
Sleeping
import logging | |
logger = logging.getLogger(__name__) | |
logging.basicConfig(level=logging.INFO) | |
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 | |
import os | |
import tempfile | |
# --- Helper Functions --- | |
def calculate_gematria_sum(text): | |
"""Calculates the gematria sum of a given text.""" | |
if text: | |
text_gematria = calculate_gematria(strip_diacritics(text)) | |
return text_gematria | |
return None | |
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") | |
return format_date(date_obj, inf_engine) | |
def month_year_to_words(date_string): | |
"""Converts a month and year in YYYY-MM format to English words.""" | |
inf_engine = inflect.engine() | |
date_obj = datetime.strptime(date_string, "%Y-%m") | |
return format_date(date_obj, inf_engine) | |
def format_date(date_obj, inf_engine): | |
"""Formats day-month-year into English words with ordinal day.""" | |
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") | |
# Tag auslesen und in Ordinalform umwandeln | |
day = date_obj.day | |
day_ordinal = number_to_ordinal_word(day) | |
return f"{day_ordinal} {month} {year_formatted}" | |
def format_year_to_words(year): | |
"""Formats a year as English words.""" | |
inf_engine = inflect.engine() | |
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='') | |
return year_words.replace(',', '') | |
def perform_gematria_calculation_for_date_range(start_date, end_date): | |
"""Performs gematria calculation for each day in a date range and groups by sum.""" | |
logger.debug(f"Start Date: {start_date}, End Date: {end_date}") | |
results = {} | |
delta = timedelta(days=1) | |
current_date = start_date | |
processed_months = set() # To track processed month-year combinations | |
processed_years = set() # To track processed years | |
while current_date <= end_date: | |
# 1) Full date calculation | |
date_string = current_date.strftime("%Y-%m-%d") | |
date_words = date_to_words(date_string) | |
gematria_sum = calculate_gematria_sum(date_words) | |
if gematria_sum not in results: | |
results[gematria_sum] = [] | |
results[gematria_sum].append({"date": date_string, "date_words": date_words}) | |
# 2) Month+Year calculation (only once per unique month-year) | |
month_year_key = current_date.strftime("%Y-%m") | |
if month_year_key not in processed_months: | |
processed_months.add(month_year_key) | |
month_year_words = f"{current_date.strftime('%B')} {format_year_to_words(current_date.year)}" | |
month_year_gematria_sum = calculate_gematria_sum(month_year_words) | |
if month_year_gematria_sum not in results: | |
results[month_year_gematria_sum] = [] | |
results[month_year_gematria_sum].append({ | |
"date": month_year_key, | |
"date_words": month_year_words | |
}) | |
# 3) Year-only calculation (only once per unique year) | |
year_key = str(current_date.year) | |
if year_key not in processed_years: | |
processed_years.add(year_key) | |
year_words = format_year_to_words(current_date.year) | |
year_gematria_sum = calculate_gematria_sum(year_words) | |
if year_gematria_sum not in results: | |
results[year_gematria_sum] = [] | |
results[year_gematria_sum].append({ | |
"date": year_key, | |
"date_words": year_words | |
}) | |
current_date += delta | |
return results | |
# --- Event Handlers --- | |
def generate_json_output(results, start_date, end_date, include_words, min_results): | |
""" | |
Erzeugt ein Dictionary (später für gr.JSON) mit Filterung nach Mindestanzahl, | |
wenn min_results nicht None ist. | |
""" | |
output = { | |
"DateRange": { | |
"StartDate": start_date.strftime("%Y-%m-%d"), | |
"EndDate": end_date.strftime("%Y-%m-%d") | |
}, | |
"Results": [] | |
} | |
for gematria_sum, entries in results.items(): | |
# Falls eine Mindestanzahl gefordert ist, filtern | |
if min_results is not None and len(entries) < min_results: | |
continue | |
group = { | |
"GematriaSum": gematria_sum, | |
"Entries": [] | |
} | |
for entry in entries: | |
entry_data = {"date": entry["date"]} | |
if include_words: | |
entry_data["date_words"] = entry["date_words"] | |
group["Entries"].append(entry_data) | |
output["Results"].append(group) | |
return output # <-- Wichtig: Als Dictionary zurückgeben | |
def perform_calculation(start_date, end_date, include_words, min_results): | |
""" | |
Führt die Gematria-Berechnung durch und gibt ein Dictionary zurück, | |
das direkt an gr.JSON übergeben werden kann. | |
""" | |
results = perform_gematria_calculation_for_date_range(start_date, end_date) | |
return generate_json_output(results, start_date, end_date, include_words, min_results) | |
def download_json(json_data, start_date, end_date): | |
""" | |
Nimmt das JSON-Dict (aus gr.JSON) und legt es als Datei ab, | |
deren Pfad wir zurückgeben. | |
Ältere Gradio-Versionen erwarten hier typischerweise einen String | |
(also File-Pfad), keinen Tuple oder dict. | |
""" | |
# Einen Dateinamen konstruieren – der taucht nur intern auf: | |
filename = f"gematria_{start_date.strftime('%Y%m%d')}_{end_date.strftime('%Y%m%d')}.json" | |
# Dictionary -> JSON-String | |
json_string = json.dumps(json_data, indent=4, ensure_ascii=False) | |
# Temporäre Datei erstellen | |
# delete=False => Datei bleibt bestehen, bis wir sie manuell entfernen wollen | |
temp = tempfile.NamedTemporaryFile(suffix=".json", delete=False) | |
temp_path = temp.name # Pfad merken | |
try: | |
# Schreiben als Bytes | |
temp.write(json_string.encode("utf-8")) | |
temp.flush() | |
finally: | |
# Datei-Handle schließen | |
temp.close() | |
# Jetzt returnen wir den Pfad | |
# => Gradio wird damit umgehen können und bietet Download an | |
return temp_path | |
# --- 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(): | |
include_date_words = gr.Checkbox(value=True, label="Include Date-Words in JSON") | |
filter_results = gr.Checkbox(value=False, label="Filter to sums with at least") | |
min_results_input = gr.Number(value=2, label="results", interactive=True, precision=0) | |
calculate_btn = gr.Button("Calculate Gematria for Date Range") | |
json_output = gr.JSON(label="JSON Output") | |
download_btn = gr.Button("Download JSON") | |
json_file = gr.File(label="Downloaded JSON") | |
# Damit wir den Wert von filter_results berücksichtigen können: | |
def handle_calculate(start_val, end_val, include_val, filter_val, min_val): | |
if not filter_val: # Checkbox nicht gesetzt | |
# => Kein Filtern, also min_results=None | |
return perform_calculation(start_val, end_val, include_val, None) | |
else: | |
# => Filter aktiviert, also min_results = min_val | |
# min_val kann float sein; auf int casten, falls gewünscht | |
return perform_calculation(start_val, end_val, include_val, int(min_val)) | |
# Button-Klick: wir rufen handle_calculate auf, | |
# das ggf. min_results auf None setzt oder den Wert übernimmt. | |
calculate_btn.click( | |
handle_calculate, | |
inputs=[start_date, end_date, include_date_words, filter_results, min_results_input], | |
outputs=[json_output], | |
api_name="calculate_gematria" | |
) | |
# Hier der "fix" im Download-Button | |
download_btn.click( | |
download_json, # unsere neue Funktion | |
inputs=[json_output, start_date, end_date], | |
outputs=[json_file] # gr.File-Element | |
) | |
filter_results.change( | |
lambda checked: gr.update(interactive=checked), | |
inputs=filter_results, | |
outputs=min_results_input | |
) | |
if __name__ == "__main__": | |
app.launch(share=False) | |