Spaces:
Sleeping
Sleeping
| import json | |
| import os | |
| import logging | |
| import sqlite3 | |
| import re | |
| from typing import Dict, List, Any | |
| from gematria import calculate_gematria, strip_diacritics | |
| from deep_translator import GoogleTranslator | |
| logger = logging.getLogger(__name__) | |
| def process_bible_files(start: int, end: int) -> Dict[int, Dict[str, Any]]: | |
| """ | |
| Processes Bible JSON files and returns a dictionary mapping book IDs to their data. | |
| Args: | |
| start: The starting book ID (inclusive). | |
| end: The ending book ID (inclusive). | |
| Returns: | |
| A dictionary where keys are book IDs and values are dictionaries | |
| containing 'title' and 'text' fields. | |
| """ | |
| base_path = "texts/bible" | |
| results = {} | |
| for i in range(start, end + 1): | |
| file_name = f"{base_path}/{i}.json" | |
| try: | |
| with open(file_name, 'r', encoding='utf-8') as file: | |
| data = json.load(file) | |
| if data: | |
| # Extract title and verses | |
| title = data.get("title", "No title") | |
| text = data.get("text", []) | |
| # Store book ID as key and book data as value | |
| results[i] = {"title": title, "text": text} | |
| except FileNotFoundError: | |
| logger.warning(f"File {file_name} not found.") | |
| except json.JSONDecodeError as e: | |
| logger.warning(f"File {file_name} could not be read as JSON: {e}") | |
| except Exception as e: | |
| logger.warning(f"Error processing {file_name}: {e}") | |
| return results | |
| def process_json_files(start, end, step, rounds="1", length=0, tlang="en", strip_spaces=True, strip_in_braces=True, | |
| strip_diacritics_value=True, translate=False): | |
| """ | |
| Processes Bible JSON files and performs ELS (Equidistant Letter Sequence) search. | |
| Parameters: | |
| - start (int): Start number of the Bible book. | |
| - end (int): End number of the Bible book. | |
| - step (int): Step size for character selection. | |
| - rounds (str): Comma-separated list of round numbers (can include negative values). | |
| - length (int): Maximum length of the result text. | |
| - tlang (str): Target language for translation. | |
| - strip_spaces (bool): Whether to remove spaces from the text. | |
| - strip_in_braces (bool): Whether to remove text within braces. | |
| - strip_diacritics_value (bool): Whether to remove diacritics from the text. | |
| - translate (bool): Whether to translate the result text. | |
| Returns: | |
| - list: A list of dictionaries containing processed data or error messages. | |
| """ | |
| logger.debug(f"Processing Bible files {start}-{end} with step {step}, rounds {rounds}") | |
| results = [] | |
| try: | |
| bible_data = process_bible_files(start, end) | |
| if not bible_data: | |
| return [{"error": f"No Bible data found for books {start}-{end}"}] | |
| rounds_list = [int(r.strip()) for r in rounds.split(",")] | |
| for book_id, book_info in bible_data.items(): | |
| book_title = book_info.get("title", "Unknown") | |
| chapters = book_info.get("text", []) | |
| if not chapters: | |
| results.append({"error": f"No text found for book {book_title} (ID: {book_id})"}) | |
| continue | |
| # Flatten the text | |
| flattened_text = "" | |
| for chapter_idx, chapter in enumerate(chapters, 1): | |
| for verse_idx, verse in enumerate(chapter, 1): | |
| if verse: | |
| flattened_text += verse + " " | |
| # Clean the text based on parameters | |
| processed_text = flattened_text.lower() | |
| if strip_in_braces: | |
| # Remove content within brackets or parentheses | |
| processed_text = re.sub(r'\[.*?\]|\(.*?\)', '', processed_text) | |
| if strip_spaces: | |
| # Remove spaces and other whitespace | |
| processed_text = re.sub(r'\s+', '', processed_text) | |
| if strip_diacritics_value: | |
| # Remove diacritics from letters | |
| processed_text = strip_diacritics(processed_text) | |
| # To match daily_psalm, process round 1 first, then other rounds | |
| sorted_rounds = sorted(rounds_list, key=lambda r: 0 if r == 1 else abs(r)) | |
| # Perform ELS search for each round | |
| for round_num in sorted_rounds: | |
| if round_num == 0: | |
| continue | |
| direction = 1 if round_num > 0 else -1 | |
| abs_round = abs(round_num) | |
| # Calculate step size | |
| actual_step = step * abs_round | |
| # Apply ELS algorithm | |
| els_result = None | |
| # Determine start index based on direction | |
| start_idx = 0 if direction > 0 else len(processed_text) - 1 | |
| # Loop through possible starting positions | |
| for i in range(abs_round): | |
| # Skip if starting position is out of bounds | |
| if start_idx + i >= len(processed_text) or start_idx - i < 0: | |
| continue | |
| # Get starting position for this round | |
| pos = start_idx + i if direction > 0 else start_idx - i | |
| # Extract letters at intervals | |
| result_text = "" | |
| while 0 <= pos < len(processed_text) and (length == 0 or len(result_text) < length): | |
| result_text += processed_text[pos] | |
| pos += actual_step * direction | |
| # Only record non-empty results | |
| if result_text: | |
| # Prepare result object | |
| result = { | |
| "result_text": result_text, | |
| "step": actual_step * direction, | |
| "start_pos": i, | |
| "book_id": book_id, | |
| "book_title": book_title, | |
| "round": round_num, | |
| "gematria": calculate_gematria(result_text) | |
| } | |
| # Translate result if requested | |
| if translate and result_text and tlang != "en": | |
| try: | |
| translator = GoogleTranslator(source='en', target=tlang) | |
| result["translated_text"] = translator.translate(result_text) | |
| except Exception as e: | |
| logger.warning(f"Translation error: {e}") | |
| result["translated_text"] = result_text | |
| # Add result to results list | |
| results.append(result) | |
| # For efficiency, once we find a valid result for this round, break the loop | |
| # This ensures we get one result per round but don't waste time on additional calculations | |
| break | |
| except Exception as e: | |
| logger.error(f"Error processing Bible files: {e}", exc_info=True) | |
| results.append({"error": f"Error processing Bible files: {str(e)}"}) | |
| return results | |
| def create_bible_display_iframe(book_title, book_id, chapter=None, verse=None): | |
| """ | |
| Creates an iframe HTML string for BibleGateway. | |
| Args: | |
| book_title (str): The title of the book. | |
| book_id (int): The ID of the book. | |
| chapter (int, optional): The chapter number. | |
| verse (int, optional): The verse number. | |
| Returns: | |
| str: An iframe HTML string for displaying the specified Bible passage. | |
| """ | |
| from urllib.parse import quote_plus | |
| # Format the passage reference | |
| if chapter and verse: | |
| reference = f"{book_title}+{chapter}:{verse}" | |
| elif chapter: | |
| reference = f"{book_title}+{chapter}" | |
| else: | |
| reference = book_title | |
| encoded_reference = quote_plus(reference) | |
| url = f"https://www.biblegateway.com/passage/?search={encoded_reference}&version=CJB" | |
| iframe = f'<iframe src="{url}" width="800" height="600"></iframe>' | |
| return iframe | |
| def find_bible_verse_by_gematria(gematria_sum, db_file="bible.db"): | |
| """ | |
| Finds a Bible verse with a matching gematria sum. | |
| Args: | |
| gematria_sum (int): The gematria sum to match. | |
| db_file (str): Path to the database file. | |
| Returns: | |
| dict or None: Dictionary with verse details or None if no match found. | |
| """ | |
| try: | |
| with sqlite3.connect(db_file) as conn: | |
| cursor = conn.cursor() | |
| cursor.execute(''' | |
| SELECT book, chapter, verse, words | |
| FROM verses | |
| WHERE gematria_sum = ? | |
| ORDER BY LENGTH(words) ASC | |
| LIMIT 1 | |
| ''', (gematria_sum,)) | |
| result = cursor.fetchone() | |
| if result: | |
| book, chapter, verse, words = result | |
| return { | |
| "book": book, | |
| "chapter": chapter, | |
| "verse": verse, | |
| "words": words | |
| } | |
| return None | |
| except sqlite3.Error as e: | |
| logger.error(f"Database error: {e}") | |
| return None | |