Spaces:
Sleeping
Sleeping
neuralworm
commited on
Commit
•
8ea2147
1
Parent(s):
62c79bd
change to multi-line input (comparison)
Browse files
app.py
CHANGED
@@ -6,6 +6,7 @@ import logging
|
|
6 |
from collections import defaultdict
|
7 |
from typing import Tuple, Dict, List
|
8 |
|
|
|
9 |
from util import process_json_files
|
10 |
from gematria import calculate_gematria
|
11 |
from deep_translator import GoogleTranslator, exceptions
|
@@ -18,7 +19,7 @@ MAX_PHRASE_LENGTH_LIMIT = 20
|
|
18 |
BATCH_SIZE = 10000
|
19 |
|
20 |
# Set up logging
|
21 |
-
logging.basicConfig(level=logging.
|
22 |
|
23 |
# Global variables
|
24 |
conn: sqlite3.Connection = None
|
@@ -45,7 +46,7 @@ def initialize_database() -> None:
|
|
45 |
verse INTEGER,
|
46 |
phrase_length INTEGER,
|
47 |
word_position TEXT,
|
48 |
-
PRIMARY KEY (gematria_sum, words, book, chapter, verse, word_position)
|
49 |
)
|
50 |
''')
|
51 |
|
@@ -208,82 +209,192 @@ def search_gematria_in_db(gematria_sum: int, max_words: int) -> List[Tuple[str,
|
|
208 |
return results
|
209 |
|
210 |
|
211 |
-
def gematria_search_interface(
|
212 |
-
"""The main function for the Gradio interface."""
|
213 |
-
if not phrase.strip():
|
214 |
-
return "Please enter a phrase."
|
215 |
-
|
216 |
global conn, book_names, gematria_cache
|
217 |
|
218 |
-
numbers = re.findall(r'\d+', phrase)
|
219 |
-
text_without_numbers = re.sub(r'\d+', '', phrase)
|
220 |
-
phrase_gematria = calculate_gematria(text_without_numbers.replace(" ", ""))
|
221 |
-
phrase_gematria += sum(int(number) for number in numbers)
|
222 |
-
|
223 |
-
if (phrase_gematria, max_words) in gematria_cache:
|
224 |
-
matching_phrases = gematria_cache[(phrase_gematria, max_words)]
|
225 |
-
else:
|
226 |
-
matching_phrases = search_gematria_in_db(phrase_gematria, max_words)
|
227 |
-
gematria_cache[(phrase_gematria, max_words)] = matching_phrases
|
228 |
-
|
229 |
-
if not matching_phrases:
|
230 |
-
return "No matching phrases found."
|
231 |
-
|
232 |
-
sorted_phrases = sorted(matching_phrases,
|
233 |
-
key=lambda x: (int(list(book_names.keys())[list(book_names.values()).index(x[1])]), x[2], x[3]))
|
234 |
-
results_by_book = defaultdict(list)
|
235 |
-
for words, book, chapter, verse, phrase_length, word_position in sorted_phrases:
|
236 |
-
results_by_book[book].append((words, chapter, verse, phrase_length, word_position))
|
237 |
-
|
238 |
results = []
|
239 |
-
|
240 |
-
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
translation = get_translation(words) if show_translation else ""
|
243 |
link = f"https://www.biblegateway.com/passage/?search={quote_plus(book)}+{chapter}%3A{verse}&version=CJB"
|
244 |
results.append(f"""
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
results.append("</div>")
|
257 |
|
258 |
# Style modified to position search on top and results below
|
259 |
style = """
|
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 |
return style + "\n".join(results)
|
286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
|
288 |
def flatten_text(text: List) -> str:
|
289 |
"""Flattens nested lists into a single list."""
|
@@ -305,8 +416,9 @@ def run_app() -> None:
|
|
305 |
|
306 |
with gr.Blocks() as iface: # Use gr.Blocks() for layout control
|
307 |
with gr.Row(): # Place inputs in a row
|
308 |
-
textbox = gr.Textbox(label="Enter word(s) or numbers")
|
309 |
-
slider = gr.Slider(label="Max Word Count in Result Phrases", minimum=1,
|
|
|
310 |
value=1)
|
311 |
checkbox = gr.Checkbox(label="Show Translation", value=True)
|
312 |
with gr.Row(): # Place buttons in a row
|
|
|
6 |
from collections import defaultdict
|
7 |
from typing import Tuple, Dict, List
|
8 |
|
9 |
+
# Assuming you have these files in your project
|
10 |
from util import process_json_files
|
11 |
from gematria import calculate_gematria
|
12 |
from deep_translator import GoogleTranslator, exceptions
|
|
|
19 |
BATCH_SIZE = 10000
|
20 |
|
21 |
# Set up logging
|
22 |
+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
23 |
|
24 |
# Global variables
|
25 |
conn: sqlite3.Connection = None
|
|
|
46 |
verse INTEGER,
|
47 |
phrase_length INTEGER,
|
48 |
word_position TEXT,
|
49 |
+
PRIMARY KEY (gematria_sum, words, book, chapter, verse, word_position)
|
50 |
)
|
51 |
''')
|
52 |
|
|
|
209 |
return results
|
210 |
|
211 |
|
212 |
+
def gematria_search_interface(phrases: str, max_words: int, show_translation: bool) -> str:
|
213 |
+
"""The main function for the Gradio interface, handling multiple phrases."""
|
|
|
|
|
|
|
214 |
global conn, book_names, gematria_cache
|
215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
results = []
|
217 |
+
all_results = [] # Store results for each phrase
|
218 |
+
middle_words_results = [] # Store middle word results for all books
|
219 |
+
|
220 |
+
phrases = phrases.strip().splitlines()
|
221 |
+
if not phrases:
|
222 |
+
return "Please enter at least one phrase."
|
223 |
+
|
224 |
+
for phrase in phrases:
|
225 |
+
if not phrase.strip():
|
226 |
+
continue # Skip empty lines
|
227 |
+
|
228 |
+
numbers = re.findall(r'\d+', phrase)
|
229 |
+
text_without_numbers = re.sub(r'\d+', '', phrase)
|
230 |
+
phrase_gematria = calculate_gematria(text_without_numbers.replace(" ", ""))
|
231 |
+
phrase_gematria += sum(int(number) for number in numbers)
|
232 |
+
|
233 |
+
if (phrase_gematria, max_words) in gematria_cache:
|
234 |
+
matching_phrases = gematria_cache[(phrase_gematria, max_words)]
|
235 |
+
else:
|
236 |
+
matching_phrases = search_gematria_in_db(phrase_gematria, max_words)
|
237 |
+
gematria_cache[(phrase_gematria, max_words)] = matching_phrases
|
238 |
+
|
239 |
+
if not matching_phrases:
|
240 |
+
results.append(f"No matching phrases found for: {phrase}")
|
241 |
+
continue
|
242 |
+
|
243 |
+
sorted_phrases = sorted(matching_phrases,
|
244 |
+
key=lambda x: (int(list(book_names.keys())[list(book_names.values()).index(x[1])]), x[2],
|
245 |
+
x[3]))
|
246 |
+
results_by_book = defaultdict(list)
|
247 |
+
for words, book, chapter, verse, phrase_length, word_position in sorted_phrases:
|
248 |
+
results_by_book[book].append((words, chapter, verse, phrase_length, word_position))
|
249 |
+
|
250 |
+
results.append(f"<h2>Results for: {phrase} (Gematria: {phrase_gematria})</h2>")
|
251 |
+
results.append("<div class='results-container'>")
|
252 |
+
for book, phrases in results_by_book.items():
|
253 |
+
for words, chapter, verse, phrase_length, word_position in phrases:
|
254 |
+
translation = get_translation(words) if show_translation else ""
|
255 |
+
link = f"https://www.biblegateway.com/passage/?search={quote_plus(book)}+{chapter}%3A{verse}&version=CJB"
|
256 |
+
results.append(f"""
|
257 |
+
<div class='result-item'>
|
258 |
+
<p><b>Book:</b> {book}</p>
|
259 |
+
<p><b>Chapter:</b> {chapter}, <b>Verse:</b> {verse}</p>
|
260 |
+
<p class='hebrew-phrase'><b>Hebrew Phrase:</b> {words}</p>
|
261 |
+
<p><b>Translation:</b> {translation}</p>
|
262 |
+
<p><b>Phrase Length:</b> {phrase_length} words</p>
|
263 |
+
<p><b>Phrase Gematria:</b> {phrase_gematria}</p>
|
264 |
+
<p><b>Word Position in the Tanach:</b> {word_position}</p>
|
265 |
+
<a href='{link}' target='_blank' class='bible-link'>[See on Bible Gateway]</a>
|
266 |
+
</div>
|
267 |
+
""")
|
268 |
+
results.append("</div>")
|
269 |
+
|
270 |
+
all_results.append(results_by_book) # Store results by book without the phrase
|
271 |
+
|
272 |
+
# Calculate middle words for all input lines
|
273 |
+
if len(all_results) >= 2:
|
274 |
+
results.append("<h2>Middle Words:</h2>")
|
275 |
+
results.append("<div class='results-container'>")
|
276 |
+
|
277 |
+
common_books = set.intersection(*[set(results.keys()) for results in all_results])
|
278 |
+
logging.debug(f"Common books: {common_books}")
|
279 |
+
|
280 |
+
for book in common_books:
|
281 |
+
logging.debug(f"Processing book: {book}")
|
282 |
+
|
283 |
+
# Find nearest positions for all phrases in the current book
|
284 |
+
nearest_positions = find_nearest_positions([results[book] for results in all_results])
|
285 |
+
logging.debug(f"Nearest positions in {book}: {nearest_positions}")
|
286 |
+
|
287 |
+
if nearest_positions:
|
288 |
+
middle_word_position = sum(nearest_positions) / len(nearest_positions)
|
289 |
+
logging.debug(f"Calculated middle word position in {book}: {middle_word_position}")
|
290 |
+
|
291 |
+
start_position = int(middle_word_position)
|
292 |
+
end_position = start_position + 1 if middle_word_position % 1 != 0 else start_position
|
293 |
+
logging.debug(f"Middle word position range in {book}: {start_position}-{end_position}")
|
294 |
+
|
295 |
+
middle_words_data = get_words_from_db(book, start_position, end_position)
|
296 |
+
logging.debug(f"Middle words data fetched from database: {middle_words_data}")
|
297 |
+
|
298 |
+
if middle_words_data:
|
299 |
+
# Store middle word data along with book name for sorting
|
300 |
+
middle_words_results.extend([(book, data) for data in middle_words_data])
|
301 |
+
else:
|
302 |
+
# Handle edge case: fetch words independently for start and end positions
|
303 |
+
logging.debug(f"No middle words found for range {start_position}-{end_position}. "
|
304 |
+
f"Fetching words independently.")
|
305 |
+
middle_words_data_start = get_words_from_db(book, start_position, start_position)
|
306 |
+
middle_words_data_end = get_words_from_db(book, end_position, end_position)
|
307 |
+
|
308 |
+
if middle_words_data_start or middle_words_data_end:
|
309 |
+
middle_words_results.extend([(book, data) for data in middle_words_data_start + middle_words_data_end])
|
310 |
+
|
311 |
+
# Sort middle words results by book order before displaying
|
312 |
+
middle_words_results.sort(key=lambda x: int(list(book_names.keys())[list(book_names.values()).index(x[0])]))
|
313 |
+
|
314 |
+
for book, (words, chapter, verse, phrase_length, word_position) in middle_words_results:
|
315 |
translation = get_translation(words) if show_translation else ""
|
316 |
link = f"https://www.biblegateway.com/passage/?search={quote_plus(book)}+{chapter}%3A{verse}&version=CJB"
|
317 |
results.append(f"""
|
318 |
+
<div class='result-item'>
|
319 |
+
<p><b>Book:</b> {book}</p>
|
320 |
+
<p><b>Chapter:</b> {chapter}, <b>Verse:</b> {verse}</p>
|
321 |
+
<p class='hebrew-phrase'><b>Hebrew Phrase:</b> {words}</p>
|
322 |
+
<p><b>Translation:</b> {translation}</p>
|
323 |
+
<p><b>Phrase Length:</b> {phrase_length} words</p>
|
324 |
+
<p><b>Word Position in the Tanach:</b> {word_position}</p>
|
325 |
+
<a href='{link}' target='_blank' class='bible-link'>[See on Bible Gateway]</a>
|
326 |
+
</div>
|
327 |
+
""")
|
328 |
+
results.append("</div>")
|
|
|
329 |
|
330 |
# Style modified to position search on top and results below
|
331 |
style = """
|
332 |
+
<style>
|
333 |
+
.results-container {
|
334 |
+
display: grid;
|
335 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
336 |
+
gap: 20px;
|
337 |
+
width: 100%; /* Make results container take full width */
|
338 |
+
}
|
339 |
+
.result-item {
|
340 |
+
border: 1px solid #ccc;
|
341 |
+
padding: 15px;
|
342 |
+
border-radius: 5px;
|
343 |
+
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
|
344 |
+
}
|
345 |
+
.hebrew-phrase {
|
346 |
+
font-family: 'SBL Hebrew', 'Ezra SIL', serif;
|
347 |
+
direction: rtl;
|
348 |
+
}
|
349 |
+
.bible-link {
|
350 |
+
display: block;
|
351 |
+
margin-top: 10px;
|
352 |
+
color: #007bff;
|
353 |
+
text-decoration: none;
|
354 |
+
}
|
355 |
+
</style>
|
356 |
+
"""
|
357 |
return style + "\n".join(results)
|
358 |
|
359 |
+
def find_nearest_positions(results_lists: List[List]) -> List[int]:
|
360 |
+
"""Finds the nearest word positions among multiple lists of results."""
|
361 |
+
nearest_positions = []
|
362 |
+
for i in range(len(results_lists)):
|
363 |
+
positions_i = [(int(pos.split('-')[0]), int(pos.split('-')[1])) for _, _, _, _, pos in results_lists[i]] # Get start and end positions
|
364 |
+
min_distance = float('inf')
|
365 |
+
nearest_pos_start = None
|
366 |
+
nearest_pos_end = None
|
367 |
+
for j in range(len(results_lists)):
|
368 |
+
if i == j:
|
369 |
+
continue
|
370 |
+
positions_j = [(int(pos.split('-')[0]), int(pos.split('-')[1])) for _, _, _, _, pos in results_lists[j]] # Get start and end positions
|
371 |
+
for pos_i_start, pos_i_end in positions_i:
|
372 |
+
for pos_j_start, pos_j_end in positions_j:
|
373 |
+
distance = abs((pos_i_start + pos_i_end) // 2 - (pos_j_start + pos_j_end) // 2)
|
374 |
+
if distance < min_distance:
|
375 |
+
min_distance = distance
|
376 |
+
nearest_pos_start = pos_i_start # Take the start position from the first list
|
377 |
+
nearest_pos_end = pos_i_end # Take the end position from the first list
|
378 |
+
if nearest_pos_start is not None and nearest_pos_end is not None:
|
379 |
+
nearest_positions.extend([nearest_pos_start, nearest_pos_end])
|
380 |
+
return nearest_positions
|
381 |
+
|
382 |
+
|
383 |
+
def get_words_from_db(book: str, start_position: int, end_position: int) -> List[Tuple]:
|
384 |
+
"""Fetches words from the database based on the book and exact word position range."""
|
385 |
+
global conn
|
386 |
+
logging.debug(f"Fetching words from database for {book} at positions {start_position}-{end_position}")
|
387 |
+
with sqlite3.connect(DATABASE_FILE) as conn:
|
388 |
+
cursor = conn.cursor()
|
389 |
+
cursor.execute("""
|
390 |
+
SELECT words, chapter, verse, phrase_length, word_position
|
391 |
+
FROM results
|
392 |
+
WHERE book = ? AND word_position = ?
|
393 |
+
""", (book, f"{start_position}-{end_position}")) # Directly compare word_position
|
394 |
+
results = cursor.fetchall()
|
395 |
+
logging.debug(f"Words fetched from database: {results}")
|
396 |
+
return results
|
397 |
+
|
398 |
|
399 |
def flatten_text(text: List) -> str:
|
400 |
"""Flattens nested lists into a single list."""
|
|
|
416 |
|
417 |
with gr.Blocks() as iface: # Use gr.Blocks() for layout control
|
418 |
with gr.Row(): # Place inputs in a row
|
419 |
+
textbox = gr.Textbox(label="Enter word(s) or numbers (one phrase per line)", lines=5)
|
420 |
+
slider = gr.Slider(label="Max Word Count in Result Phrases", minimum=1,
|
421 |
+
maximum=MAX_PHRASE_LENGTH_LIMIT, step=1,
|
422 |
value=1)
|
423 |
checkbox = gr.Checkbox(label="Show Translation", value=True)
|
424 |
with gr.Row(): # Place buttons in a row
|