neuralworm commited on
Commit
8ea2147
1 Parent(s): 62c79bd

change to multi-line input (comparison)

Browse files
Files changed (1) hide show
  1. app.py +181 -69
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.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
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) -- Primary key constraint
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(phrase: str, max_words: int, show_translation: bool) -> str:
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
- results.append("<div class='results-container'>")
240
- for book, phrases in results_by_book.items():
241
- for words, chapter, verse, phrase_length, word_position in phrases:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- <div class='result-item'>
246
- <p><b>Book:</b> {book}</p>
247
- <p><b>Chapter:</b> {chapter}, <b>Verse:</b> {verse}</p>
248
- <p class='hebrew-phrase'><b>Hebrew Phrase:</b> {words}</p>
249
- <p><b>Translation:</b> {translation}</p>
250
- <p><b>Phrase Length:</b> {phrase_length} words</p>
251
- <p><b>Phrase Gematria:</b> {phrase_gematria}</p>
252
- <p><b>Word Position in the Tanach:</b> {word_position}</p>
253
- <a href='{link}' target='_blank' class='bible-link'>[See on Bible Gateway]</a>
254
- </div>
255
- """)
256
- results.append("</div>")
257
 
258
  # Style modified to position search on top and results below
259
  style = """
260
- <style>
261
- .results-container {
262
- display: grid;
263
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
264
- gap: 20px;
265
- width: 100%; /* Make results container take full width */
266
- }
267
- .result-item {
268
- border: 1px solid #ccc;
269
- padding: 15px;
270
- border-radius: 5px;
271
- box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
272
- }
273
- .hebrew-phrase {
274
- font-family: 'SBL Hebrew', 'Ezra SIL', serif;
275
- direction: rtl;
276
- }
277
- .bible-link {
278
- display: block;
279
- margin-top: 10px;
280
- color: #007bff;
281
- text-decoration: none;
282
- }
283
- </style>
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, maximum=MAX_PHRASE_LENGTH_LIMIT, step=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