Spaces:
Sleeping
Sleeping
File size: 13,489 Bytes
e8510d3 | 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 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | import json
import os
import logging
import sqlite3
import re
from gematria import calculate_gematria, strip_diacritics
from deep_translator import GoogleTranslator
logger = logging.getLogger(__name__)
def get_sura_count() -> int:
"""Returns the total number of suras in the Quran."""
base_path = "texts/quran"
# Count the number of JSON files in the quran directory
try:
files = [f for f in os.listdir(base_path) if f.endswith('.json')]
return len(files)
except FileNotFoundError:
logger.error(f"Directory {base_path} not found.")
return 114 # Default number of suras in the Quran
def get_quran_text_and_map():
"""
Loads all Quran text and creates a character-to-location map.
This is a helper to avoid repeatedly loading and processing the text.
"""
# This could be cached in memory for performance if the app is long-running
all_text = ""
char_map = [] # List of (sura_id, sura_name, verse_id) for each character
sura_count = get_sura_count()
for sura_num in range(1, sura_count + 1):
sura_str = f"{sura_num:03d}"
file_path = f"texts/quran/{sura_str}.json"
if not os.path.exists(file_path):
continue
try:
with open(file_path, 'r', encoding='utf-8') as f:
sura_data = json.load(f)
except (json.JSONDecodeError, FileNotFoundError):
continue
sura_name = sura_data.get('name', f"Sura {sura_num}")
if all_text:
all_text += " "
verses = sura_data.get('text', []) or sura_data.get('verse', {})
if isinstance(verses, dict):
verses = [verses[key] for key in sorted(verses.keys())]
for verse_idx, verse in enumerate(verses, 1):
if verse:
# Add original verse text to all_text
all_text += verse + " "
# For the char_map, use the cleaned version
cleaned_verse = strip_diacritics(verse).replace(" ", "")
for _ in cleaned_verse:
char_map.append((sura_num, sura_name, verse_idx))
# Clean up the text for ELS: strip diacritics, remove any special characters, etc.
clean_text = strip_diacritics(all_text)
# The reference implementation is more aggressive in cleaning.
clean_text = ''.join(c for c in clean_text if c.isalpha() or c.isspace())
text_no_spaces = clean_text.replace(" ", "")
return text_no_spaces, char_map
def get_first_els_result_quran(gematria_sum: int, tlang: str = "en", cached_process_func=None) -> dict:
"""
Gets the first ELS result from the Quran using the gematria sum as the step.
This version is aligned with the logic from the reference 'daily_psalm' project.
"""
import hashlib
logger.debug(f"Entering get_first_els_result_quran (reference logic) with gematria_sum: {gematria_sum}")
# Caching logic remains similar
cache_key = f"quran_els_ref_{gematria_sum}_{tlang}"
cache_file = "els_cache.db"
try:
with sqlite3.connect(cache_file) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT results FROM els_cache WHERE query_hash = ?",
(hashlib.sha256(cache_key.encode()).hexdigest(),))
result = cursor.fetchone()
if result:
logger.info(f"Cache hit for Quran ELS query: {cache_key}")
return json.loads(result[0])
except sqlite3.Error as e:
logger.error(f"Database error checking cache: {e}")
logger.info(f"Cache miss for Quran ELS query: {cache_key}, performing search")
text_no_spaces, char_map = get_quran_text_and_map()
logger.debug(f"Processed text length (for ELS): {len(text_no_spaces)}")
logger.debug(f"First 100 chars of processed text: {text_no_spaces[:100]}")
result = None
# Start positions to try (first 100 positions for better coverage)
for start_pos in range(min(100, len(text_no_spaces))):
extracted = ""
positions = []
pos = start_pos
# Extract until the end of the text is reached
while pos < len(text_no_spaces):
extracted += text_no_spaces[pos]
positions.append(pos)
pos += gematria_sum
if len(extracted) >= 3: # At least 3 characters
first_pos = positions[0]
last_pos = positions[-1]
if first_pos < len(char_map) and last_pos < len(char_map):
first_loc = char_map[first_pos]
last_loc = char_map[last_pos]
result = {
"result_text": extracted,
"source": "Quran",
"start_position": start_pos,
"step": gematria_sum,
"start_sura": first_loc[0],
"start_sura_name": first_loc[1],
"start_verse": first_loc[2],
"end_sura": last_loc[0],
"end_sura_name": last_loc[1],
"end_verse": last_loc[2],
"positions": positions,
"gematria": calculate_gematria(extracted) # Add gematria here
}
logger.debug(f"Found ELS result: {result}")
break # Found a result, stop searching
else:
logger.warning(f"Character position mapping inconsistency: {first_pos}, {last_pos} vs {len(char_map)}")
continue
if result:
try:
with sqlite3.connect(cache_file) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS els_cache (
query_hash TEXT PRIMARY KEY, function_name TEXT,
args TEXT, kwargs TEXT, results TEXT
)
''')
cursor.execute(
"INSERT OR REPLACE INTO els_cache (query_hash, function_name, args, kwargs, results) VALUES (?, ?, ?, ?, ?)",
(hashlib.sha256(cache_key.encode()).hexdigest(), "get_first_els_result_quran_ref",
json.dumps([gematria_sum]), json.dumps({"tlang": tlang}), json.dumps(result)))
conn.commit()
logger.debug("Cached Quran ELS results in database.")
except sqlite3.Error as e:
logger.error(f"Database error caching results: {e}")
logger.debug(f"Exiting get_first_els_result_quran, returning: {result}")
return result
def find_shortest_sura_match(gematria_sum, db_file='abjad.db'):
"""
Finds the shortest Sura (Aya) entry in the database with matching gematria sum.
Parameters:
- gematria_sum (int): The gematria sum to match.
- db_file (str): Path to the database file.
Returns:
- dict or None: Dictionary with match details or None if no match found.
"""
logger.debug(f"Finding shortest sura match for gematria sum: {gematria_sum}")
try:
with sqlite3.connect(db_file) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT words, book, chapter, verse
FROM results
WHERE gematria_sum = ?
ORDER BY LENGTH(words) ASC
LIMIT 1
''', (gematria_sum,))
result = cursor.fetchone()
if result:
logger.debug(f"Shortest sura match found: {result}")
return {
"words": result[0],
"book": result[1],
"chapter": result[2],
"verse": result[3]
}
logger.debug("No matching sura found.")
return None
except sqlite3.Error as e:
logger.error(f"Database error: {e}")
return None
def create_quran_display_iframe(sura, verse=None):
"""
Creates an iframe HTML string for Quran.com.
Parameters:
- sura (str or int): The sura name or number.
- verse (str or int, optional): The verse number.
Returns:
- str: An iframe HTML string for displaying the specified Quran passage.
"""
# Format URL based on parameters
if verse:
url = f"https://quran.com/{sura}/{verse}"
else:
url = f"https://quran.com/{sura}"
# Create iframe HTML
iframe = f'<iframe src="{url}" width="800" height="600"></iframe>'
return iframe
def initialize_quran_database(db_file='abjad.db', max_phrase_length=3):
"""
Initialize the database with Quran verses and their gematria sums.
Parameters:
- db_file (str): Path to the database file.
- max_phrase_length (int): Maximum number of words to include in phrases.
Returns:
- bool: True if initialization was successful, False otherwise.
"""
logger.info(f"Initializing Quran database {db_file} with max phrase length {max_phrase_length}")
try:
# Create database and tables if they don't exist
with sqlite3.connect(db_file) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
book TEXT,
chapter INTEGER,
verse INTEGER,
words TEXT,
gematria_sum INTEGER
)
''')
# Check if there are already Quran entries in the database
cursor.execute("SELECT COUNT(*) FROM results WHERE book != 'Psalms'")
count = cursor.fetchone()[0]
if count > 0:
logger.info(f"Database already contains {count} Quran entries. Skipping initialization.")
return True
# Process Quran files
logger.info("Processing Quran files...")
quran_base_path = "texts/quran"
# Get list of all Quran JSON files
quran_files = []
try:
for filename in os.listdir(quran_base_path):
if filename.endswith('.json'):
quran_files.append(os.path.join(quran_base_path, filename))
except FileNotFoundError:
logger.error(f"Quran texts directory not found: {quran_base_path}")
return False
# Process each sura file
for file_path in sorted(quran_files):
try:
with open(file_path, 'r', encoding='utf-8') as f:
sura_data = json.load(f)
# Extract sura details
sura_name = sura_data.get('name', os.path.basename(file_path))
sura_number = int(os.path.basename(file_path).split('.')[0])
verses = sura_data.get('text', [])
logger.debug(f"Processing Sura {sura_number}: {sura_name} with {len(verses)} verses")
# Process each verse
for verse_idx, verse_text in enumerate(verses, 1):
if not verse_text:
continue
# Split verse into words
words = verse_text.split()
# Generate phrases of different lengths
for length in range(1, min(max_phrase_length + 1, len(words) + 1)):
for i in range(len(words) - length + 1):
phrase = ' '.join(words[i:i+length])
# Calculate gematria value
gematria_sum = calculate_gematria(strip_diacritics(phrase.lower()))
# Skip if gematria sum is 0
if gematria_sum == 0:
continue
# Insert into database
cursor.execute('''
INSERT INTO results (book, chapter, verse, words, gematria_sum)
VALUES (?, ?, ?, ?, ?)
''', (sura_name, sura_number, verse_idx, phrase, gematria_sum))
except Exception as e:
logger.error(f"Error processing {file_path}: {str(e)}")
# Commit changes
conn.commit()
# Count total entries
cursor.execute("SELECT COUNT(*) FROM results WHERE book != 'Psalms'")
count = cursor.fetchone()[0]
logger.info(f"Successfully initialized Quran database with {count} entries")
return True
except sqlite3.Error as e:
logger.error(f"Database error during initialization: {str(e)}")
return False
except Exception as e:
logger.error(f"Error initializing database: {str(e)}")
return False
|