neuralworm's picture
fix
287228a
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)