neuralworm commited on
Commit
41387a4
ยท
1 Parent(s): 71fa3d9
Files changed (3) hide show
  1. .gitignore +3 -0
  2. app-webshell.py +114 -0
  3. app.py +279 -101
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ venv-xor-tanakh2
2
+ __pycache__
3
+ .gradio
app-webshell.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
+ import gradio as gr
4
+ import subprocess
5
+
6
+ # --- SICHERHEITSHINWEIS ---
7
+ # Diese Webshell fรผhrt beliebigen Code auf dem Server aus.
8
+ # Machen Sie diesen Space NICHT รถffentlich, es sei denn, Sie verstehen die Risiken.
9
+ # Jeder, der Zugriff auf diesen Space hat, kann Befehle ausfรผhren.
10
+ # Am besten nur fรผr private oder organisatorische Spaces verwenden.
11
+ # -------------------------
12
+
13
+ WARNING_MESSAGE = """
14
+ โš ๏ธ **SICHERHEITSWARNUNG** โš ๏ธ
15
+
16
+ Dies ist eine funktionierende Web-Shell. Jeder Befehl, den Sie hier eingeben,
17
+ wird direkt auf dem Server des Hugging Face Space ausgefรผhrt.
18
+
19
+ - **Machen Sie diesen Space nicht รถffentlich!** Fremde kรถnnten ihn missbrauchen, um den Container zu beschรคdigen, Angriffe zu starten oder Ihre Daten (falls vorhanden) zu kompromittieren.
20
+ - Nutzen Sie diesen Space nur fรผr private Zwecke oder innerhalb Ihrer Organisation.
21
+ - Seien Sie vorsichtig mit den Befehlen, die Sie ausfรผhren (z. B. `rm -rf /`).
22
+ """
23
+
24
+ def execute_command(command):
25
+ """
26
+ Fรผhrt einen Shell-Befehl sicher aus und gibt stdout und stderr zurรผck.
27
+ """
28
+ if not command:
29
+ return "Bitte geben Sie einen Befehl ein.", ""
30
+
31
+ try:
32
+ # Fรผhre den Befehl aus.
33
+ # shell=True ist notwendig, um eine "echte" Shell-Umgebung zu haben
34
+ # (z.B. fรผr Pipes | oder cd), aber es ist auch ein Sicherheitsrisiko.
35
+ # Deswegen die groรŸe Warnung oben!
36
+ process = subprocess.run(
37
+ command,
38
+ shell=True,
39
+ capture_output=True,
40
+ text=True,
41
+ timeout=600 # Timeout von 60 Sekunden, um Endlos-Prozesse zu verhindern
42
+ )
43
+
44
+ # Kombiniere Standardausgabe und Standardfehler fรผr die Anzeige
45
+ stdout = process.stdout
46
+ stderr = process.stderr
47
+
48
+ # Gib eine informative Nachricht zurรผck, wenn kein Output kam
49
+ if not stdout and not stderr:
50
+ return "Befehl ausgefรผhrt, keine Ausgabe.", ""
51
+
52
+ return stdout, stderr
53
+
54
+ except subprocess.TimeoutExpired:
55
+ return "", "Fehler: Der Befehl hat das Zeitlimit von 60 Sekunden รผberschritten."
56
+ except Exception as e:
57
+ return "", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}"
58
+
59
+ # Wir definieren das Gradio Interface
60
+ with gr.Blocks(theme=gr.themes.Monochrome(), css=".gradio-container {background-color: #1a1a1a;}") as demo:
61
+ gr.Markdown(f"# ๐Ÿ Python Web-Shell fรผr Hugging Face Spaces")
62
+ gr.Markdown(WARNING_MESSAGE)
63
+
64
+ with gr.Row():
65
+ command_input = gr.Textbox(
66
+ label="Shell-Befehl eingeben",
67
+ placeholder="z.B. ls -l, whoami, pwd, pip list"
68
+ )
69
+
70
+ execute_button = gr.Button("๐Ÿš€ Ausfรผhren")
71
+
72
+ with gr.Row():
73
+ with gr.Column(scale=2):
74
+ gr.Markdown("### โœ… Standardausgabe (stdout)")
75
+ # KORREKTUR: Der Parameter `language="bash"` wurde entfernt.
76
+ output_stdout = gr.Code(label="stdout", interactive=False)
77
+
78
+ with gr.Column(scale=1):
79
+ gr.Markdown("### โŒ Standardfehler (stderr)")
80
+ # KORREKTUR: Der Parameter `language="bash"` wurde entfernt.
81
+ output_stderr = gr.Code(label="stderr", interactive=False)
82
+
83
+ # Verknรผpfe die Button-Klicks und die Eingabe mit der Funktion
84
+ execute_button.click(
85
+ fn=execute_command,
86
+ inputs=command_input,
87
+ outputs=[output_stdout, output_stderr]
88
+ )
89
+ command_input.submit(
90
+ fn=execute_command,
91
+ inputs=command_input,
92
+ outputs=[output_stdout, output_stderr]
93
+ )
94
+
95
+ gr.Markdown("---")
96
+ gr.Markdown("### Nรผtzliche Beispielbefehle:")
97
+ gr.Examples(
98
+ examples=[
99
+ "ls -la",
100
+ "pwd",
101
+ "whoami",
102
+ "env",
103
+ "pip list",
104
+ "df -h",
105
+ "cat /proc/cpuinfo",
106
+ "uname -a"
107
+ ],
108
+ inputs=command_input
109
+ )
110
+
111
+
112
+ # Starte die App
113
+ if __name__ == "__main__":
114
+ demo.launch()
app.py CHANGED
@@ -1,114 +1,292 @@
1
- # app.py
2
-
3
  import gradio as gr
4
- import subprocess
 
 
 
 
 
 
 
 
 
 
5
 
6
- # --- SICHERHEITSHINWEIS ---
7
- # Diese Webshell fรผhrt beliebigen Code auf dem Server aus.
8
- # Machen Sie diesen Space NICHT รถffentlich, es sei denn, Sie verstehen die Risiken.
9
- # Jeder, der Zugriff auf diesen Space hat, kann Befehle ausfรผhren.
10
- # Am besten nur fรผr private oder organisatorische Spaces verwenden.
11
- # -------------------------
12
 
13
- WARNING_MESSAGE = """
14
- โš ๏ธ **SICHERHEITSWARNUNG** โš ๏ธ
15
 
16
- Dies ist eine funktionierende Web-Shell. Jeder Befehl, den Sie hier eingeben,
17
- wird direkt auf dem Server des Hugging Face Space ausgefรผhrt.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- - **Machen Sie diesen Space nicht รถffentlich!** Fremde kรถnnten ihn missbrauchen, um den Container zu beschรคdigen, Angriffe zu starten oder Ihre Daten (falls vorhanden) zu kompromittieren.
20
- - Nutzen Sie diesen Space nur fรผr private Zwecke oder innerhalb Ihrer Organisation.
21
- - Seien Sie vorsichtig mit den Befehlen, die Sie ausfรผhren (z. B. `rm -rf /`).
22
- """
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- def execute_command(command):
25
- """
26
- Fรผhrt einen Shell-Befehl sicher aus und gibt stdout und stderr zurรผck.
27
- """
28
- if not command:
29
- return "Bitte geben Sie einen Befehl ein.", ""
 
 
 
30
 
31
  try:
32
- # Fรผhre den Befehl aus.
33
- # shell=True ist notwendig, um eine "echte" Shell-Umgebung zu haben
34
- # (z.B. fรผr Pipes | oder cd), aber es ist auch ein Sicherheitsrisiko.
35
- # Deswegen die groรŸe Warnung oben!
36
- process = subprocess.run(
37
- command,
38
- shell=True,
39
- capture_output=True,
40
- text=True,
41
- timeout=600 # Timeout von 60 Sekunden, um Endlos-Prozesse zu verhindern
42
- )
43
-
44
- # Kombiniere Standardausgabe und Standardfehler fรผr die Anzeige
45
- stdout = process.stdout
46
- stderr = process.stderr
47
-
48
- # Gib eine informative Nachricht zurรผck, wenn kein Output kam
49
- if not stdout and not stderr:
50
- return "Befehl ausgefรผhrt, keine Ausgabe.", ""
51
-
52
- return stdout, stderr
53
-
54
- except subprocess.TimeoutExpired:
55
- return "", "Fehler: Der Befehl hat das Zeitlimit von 60 Sekunden รผberschritten."
56
  except Exception as e:
57
- return "", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}"
58
-
59
- # Wir definieren das Gradio Interface
60
- with gr.Blocks(theme=gr.themes.Monochrome(), css=".gradio-container {background-color: #1a1a1a;}") as demo:
61
- gr.Markdown(f"# ๐Ÿ Python Web-Shell fรผr Hugging Face Spaces")
62
- gr.Markdown(WARNING_MESSAGE)
63
-
64
- with gr.Row():
65
- command_input = gr.Textbox(
66
- label="Shell-Befehl eingeben",
67
- placeholder="z.B. ls -l, whoami, pwd, pip list"
68
- )
69
-
70
- execute_button = gr.Button("๐Ÿš€ Ausfรผhren")
71
-
72
- with gr.Row():
73
- with gr.Column(scale=2):
74
- gr.Markdown("### โœ… Standardausgabe (stdout)")
75
- # KORREKTUR: Der Parameter `language="bash"` wurde entfernt.
76
- output_stdout = gr.Code(label="stdout", interactive=False)
77
-
78
- with gr.Column(scale=1):
79
- gr.Markdown("### โŒ Standardfehler (stderr)")
80
- # KORREKTUR: Der Parameter `language="bash"` wurde entfernt.
81
- output_stderr = gr.Code(label="stderr", interactive=False)
82
-
83
- # Verknรผpfe die Button-Klicks und die Eingabe mit der Funktion
84
- execute_button.click(
85
- fn=execute_command,
86
- inputs=command_input,
87
- outputs=[output_stdout, output_stderr]
88
- )
89
- command_input.submit(
90
- fn=execute_command,
91
- inputs=command_input,
92
- outputs=[output_stdout, output_stderr]
93
- )
94
 
95
- gr.Markdown("---")
96
- gr.Markdown("### Nรผtzliche Beispielbefehle:")
97
- gr.Examples(
98
- examples=[
99
- "ls -la",
100
- "pwd",
101
- "whoami",
102
- "env",
103
- "pip list",
104
- "df -h",
105
- "cat /proc/cpuinfo",
106
- "uname -a"
107
- ],
108
- inputs=command_input
109
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- # Starte die App
113
  if __name__ == "__main__":
114
- demo.launch()
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import json
3
+ import logging
4
+ import argparse
5
+ import sys
6
+ import os
7
+ import math
8
+ import pickle
9
+ from deep_translator import GoogleTranslator
10
+ from gematria import calculate_gematria
11
+ from collections import defaultdict
12
+ from typing import Dict, List, Any, Optional
13
 
14
+ # --- Configuration ---
15
+ # Logging is kept for file-based or production logging, but we'll use print() for immediate console debug
16
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
+ BOOK_RANGE = range(1, 40)
18
+ CACHE_FILE = "tanakh_phrasedict.cache"
 
19
 
20
+ # --- Core Logic Functions ---
 
21
 
22
+ def get_power_result(total_sum: int, query_value: int) -> int:
23
+ """Calculates the power or root result."""
24
+ if total_sum <= 0 or query_value <= 1:
25
+ return 1
26
+ if query_value <= total_sum:
27
+ try:
28
+ exponent = int(math.floor(math.log(total_sum, query_value)))
29
+ return query_value ** exponent
30
+ except (ValueError, OverflowError):
31
+ return 1
32
+ else:
33
+ for n in range(2, 65):
34
+ try:
35
+ root_result = query_value ** (1.0 / n)
36
+ if root_result <= total_sum:
37
+ return math.ceil(root_result)
38
+ except (ValueError, OverflowError):
39
+ return 1
40
+ return 1
41
 
42
+ def find_all_matching_phrases(target_sum: int, phrase_dictionary: Dict[int, List[Dict]]) -> List[Dict]:
43
+ """Finds all phrases matching a target Gematria."""
44
+ return phrase_dictionary.get(int(target_sum), [])
45
+
46
+ # --- Global State: Load dictionary once at startup ---
47
+ try:
48
+ if not os.path.exists(CACHE_FILE):
49
+ raise FileNotFoundError(f"ERROR: Cache file '{CACHE_FILE}' not found. Please run 'build_indices.py' first.")
50
+ logging.info(f"Loading phrase dictionary from cache: {CACHE_FILE}")
51
+ with open(CACHE_FILE, 'rb') as f:
52
+ phrase_dictionary: Optional[Dict[int, List[Dict]]] = pickle.load(f)
53
+ logging.info("Phrase dictionary loaded successfully for the Gradio app.")
54
+ except (FileNotFoundError, IOError, pickle.UnpicklingError) as e:
55
+ logging.error(str(e))
56
+ phrase_dictionary = None
57
 
58
+ # --- Main Analysis Function for Gradio ---
59
+
60
+ def run_analysis(query: str, translate: bool, process_verses: int, results_per_verse: int, xor_depth: int, progress=gr.Progress(track_tqdm=True)):
61
+ """The main analysis function called by the Gradio interface."""
62
+ if phrase_dictionary is None:
63
+ return "## Fatal Error\nCould not start analysis. The phrase dictionary cache file (`tanakh_phrasedict.cache`) is missing or corrupt. Please run `build_indices.py` and restart the app."
64
+
65
+ print("\n--- NEW ANALYSIS RUN ---") # Console Debug
66
+ output_lines = []
67
 
68
  try:
69
+ query_value = calculate_gematria(query)
70
+ if query_value <= 1 and query:
71
+ return f"## Error\nQuery '{query}' has an invalid Gematria value ({query_value}). Please enter a valid query."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  except Exception as e:
73
+ return f"## Error\nCould not calculate Gematria for query '{query}'. Details: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ progress(0, desc="Initializing...")
76
+ translator = None
77
+ if translate:
78
+ try:
79
+ translator = GoogleTranslator(source='iw', target='en')
80
+ except Exception as e:
81
+ logging.error(f"Could not initialize translator: {e}")
82
+ output_lines.append(f"**Warning:** Could not initialize translator: {e}")
83
+
84
+ output_lines.append(f"## XOR Gematria Resonance Analysis for: `{query}`")
85
+
86
+ verses_processed = 0
87
+ resonance_count = 0
88
+
89
+ # Using a generator to handle the nested loops cleanly and break out
90
+ def get_verses():
91
+ for book_num in BOOK_RANGE:
92
+ filepath = f"texts/torah/{book_num:02}.json"
93
+ if not os.path.exists(filepath): continue
94
+ with open(filepath, 'r', encoding='utf-8') as f:
95
+ data = json.load(f)
96
+ for chap_idx, chapter in enumerate(data.get("text", []), start=1):
97
+ for verse_idx, verse_text in enumerate(chapter, start=1):
98
+ yield (book_num, chap_idx, verse_idx, verse_text)
99
+
100
+ for book_num, chap_idx, verse_idx, verse_text in get_verses():
101
+ # Correctly handle the processing limit
102
+ if process_verses and verses_processed >= process_verses:
103
+ print(f"DEBUG: Processing limit of {process_verses} verses reached. Stopping analysis.")
104
+ break
105
+ verses_processed += 1
106
+ progress(verses_processed / process_verses, desc=f"Analyzing Verse {verses_processed}/{process_verses}")
107
+
108
+ verse_sum = calculate_gematria(verse_text)
109
+ if verse_sum <= 1: continue
110
+
111
+ power_result = get_power_result(verse_sum, query_value)
112
+ main_target_sum = verse_sum ^ power_result
113
+ main_matches = find_all_matching_phrases(main_target_sum, phrase_dictionary)
114
+
115
+ verse_ref = f"B{book_num:02d}, C{chap_idx}, V{verse_idx}"
116
+ print(f"DEBUG: Analyzing [{verse_ref}] | Verse Sum: {verse_sum}, Power/Root: {power_result}, Main Target: {main_target_sum}") # Console Debug
117
+
118
+ if not main_matches:
119
+ print("DEBUG: No main resonance found. Skipping.") # Console Debug
120
+ continue
121
+
122
+ resonance_count += 1
123
+ print(f"DEBUG: Found Resonance #{resonance_count}!") # Console Debug
124
+
125
+ output_lines.append("\n---\n")
126
+ output_lines.append(f"### Resonance #{resonance_count} in [{verse_ref}]")
127
+ output_lines.append(f"> {verse_text.strip()}\n")
128
+
129
+ output_lines.append("```")
130
+ output_lines.append(f"Verse Sum (X) : {verse_sum} | Query: \"{query}\" (G: {query_value}) | Power/Root (Y): {power_result}")
131
+ output_lines.append("```\n")
132
+
133
+ def format_matches(matches: List[Dict], title: str, calculation_str: str):
134
+ if not matches: return
135
+
136
+ matches.sort(key=lambda p: (p.get('freq', 0) / p.get('words', 99)), reverse=True)
137
+ matches_to_show = matches[:results_per_verse]
138
 
139
+ output_lines.append(f"**{title}:** `{calculation_str}`")
140
+
141
+ for match in matches_to_show:
142
+ translation_str = ""
143
+ if translator:
144
+ try:
145
+ translation_str = translator.translate(match['text'])
146
+ except Exception:
147
+ translation_str = "[Translation failed]"
148
+
149
+ score = (p.get('freq', 0) / p.get('words', 99)) if (p:=match).get('words') else 0
150
+ gematria_val = calculate_gematria(match['text'])
151
+
152
+ output_lines.append(f" * **{match['text']}**")
153
+ output_lines.append(f" `G: {gematria_val}, Words: {match.get('words', 'N/A')}, Freq: {match.get('freq', 'N/A')}, Score: {score:.2f}`")
154
+ if translation_str:
155
+ output_lines.append(f"\n*Translation: \"{translation_str}\"*")
156
+ output_lines.append("")
157
+
158
+ calc_str = f"[{verse_sum}] ^ [{power_result}] โ†’ [G_target:{main_target_sum}]"
159
+ format_matches(main_matches, "Main Resonance", calc_str)
160
+
161
+ if xor_depth > 0:
162
+ output_lines.append(f"**Bitplane Variations of the Result ({main_target_sum}):**")
163
+ for depth in range(xor_depth):
164
+ bit_flip = 1 << depth
165
+ target_sum = main_target_sum ^ bit_flip
166
+ bitplane_matches = find_all_matching_phrases(target_sum, phrase_dictionary)
167
+
168
+ if bitplane_matches:
169
+ bitplane_calc_str = f"[{main_target_sum}] ^ [Bit {depth+1}] โ†’ [G_target:{target_sum}]"
170
+ format_matches(bitplane_matches, f"Variation (Depth {depth + 1})", bitplane_calc_str)
171
+
172
+ if resonance_count == 0:
173
+ output_lines.append("\n**No resonances found. Consider increasing 'Verses to Process' or trying a different query.**")
174
+
175
+ print("--- ANALYSIS COMPLETE ---") # Console Debug
176
+ return "\n".join(output_lines)
177
+
178
+ # --- Gradio UI Definition ---
179
+ # Custom CSS for a professional dark theme inspired by the screenshot
180
+ custom_css = """
181
+ #output_markdown h3 {
182
+ color: #f97316; /* Vibrant orange for main resonance headers */
183
+ border-bottom: 2px solid #374151;
184
+ padding-bottom: 8px;
185
+ margin-top: 24px;
186
+ }
187
+ #output_markdown blockquote {
188
+ background-color: #1f2937;
189
+ border-left: 5px solid #f97316;
190
+ padding: 12px;
191
+ font-style: italic;
192
+ color: #d1d5db;
193
+ }
194
+ #output_markdown code {
195
+ background-color: #374151;
196
+ color: #e5e7eb;
197
+ padding: 3px 6px;
198
+ border-radius: 5px;
199
+ font-size: 0.9em;
200
+ }
201
+ """
202
+
203
+ # Using the robust Default theme and customizing it for the desired dark look
204
+ dark_theme = gr.themes.Default(
205
+ primary_hue=gr.themes.colors.orange,
206
+ secondary_hue=gr.themes.colors.blue,
207
+ neutral_hue=gr.themes.colors.slate
208
+ ).set(
209
+ body_background_fill="#0f172a",
210
+ background_fill_primary="#1e293b",
211
+ background_fill_secondary="#334155",
212
+ body_text_color="#e2e8f0",
213
+ color_accent_soft="#1e293b",
214
+ border_color_accent="#334155",
215
+ border_color_primary="#334155",
216
+ button_primary_background_fill="#f97316",
217
+ button_primary_text_color="#ffffff",
218
+ button_secondary_background_fill="#334155",
219
+ button_secondary_text_color="#e2e8f0",
220
+ )
221
+
222
+ with gr.Blocks(theme=dark_theme, css=custom_css, title="Tanakh XOR Gematria Resonance") as demo:
223
+ gr.Markdown("# ๐Ÿ“œ Tanakh XOR Gematria Resonance")
224
+
225
+ with gr.Tabs():
226
+ with gr.TabItem("XOR Gematria Resonance"):
227
+ with gr.Row():
228
+ with gr.Column(scale=1):
229
+ query = gr.Textbox(
230
+ label="Query Phrase",
231
+ placeholder="e.g., ื™ื”ื•ื”, ืืœื”ื™ื, light...",
232
+ )
233
+ run_button = gr.Button("๐Ÿ”ฎ Divine Resonance", variant="primary")
234
+
235
+ with gr.Accordion("Advanced Parameters", open=False):
236
+ process_verses = gr.Slider(
237
+ label="Verses to Process", minimum=1, maximum=35000, step=1, value=10,
238
+ info="How many verses to analyze from the start of the Tanakh."
239
+ )
240
+ results_per_verse = gr.Slider(
241
+ label="Results per Resonance", minimum=1, maximum=10, step=1, value=1,
242
+ info="How many top phrases to show for each found resonance type."
243
+ )
244
+ xor_depth = gr.Slider(
245
+ label="Bitplane Variation Depth", minimum=0, maximum=16, step=1, value=2,
246
+ info="How many bit-levels of the main result to vary and analyze."
247
+ )
248
+ translate = gr.Checkbox(label="Translate to English", value=True)
249
+
250
+ gr.Examples(
251
+ examples=[
252
+ ["ื™ื”ื•ื”"], ["ืืœื”ื™ื"], ["ืฉื›ื™ื ื”"],
253
+ ["ืžืฉื™ื— ื™ืฉืžืขืืœ"], ["ืžืื” ืฉืœื•ืฉื™ื ื•ืฉื‘ืข"], ["ืฆื“ืง ื•ืžืฉืคื˜"]
254
+ ],
255
+ inputs=[query]
256
+ )
257
+
258
+ with gr.Column(scale=3):
259
+ output_markdown = gr.Markdown(label="Resonances", elem_id="output_markdown")
260
+
261
+ with gr.TabItem("About & Help"):
262
+ gr.Markdown(
263
+ """
264
+ ### How It Works
265
+ This tool explores the numerological and structural connections within the Tanakh based on Gematria and bitwise XOR operations. It is an instrument for textual exploration, not a historical or theological authority.
266
+
267
+ 1. **Gematria Calculation:** The Gematria (numerical value) of your **Query Phrase** and each **Verse** in the Tanakh is calculated.
268
+ 2. **Power/Root Operator (Y):** To create a non-obvious link, the Query's Gematria is transformed. If it's smaller than the Verse's Gematria, its highest possible power is taken. If larger, its n-th root is taken. This becomes the "Operator" (Y).
269
+ 3. **Main Resonance:** The core operation is `Verse_Gematria (X) ^ Operator (Y)`. The result is a **Target Gematria**. The app then finds all phrases in the Tanakh with this exact numerical value. This is the "Main Resonance".
270
+ 4. **Bitplane Variations:** To explore the "fractal neighborhood" of the Main Resonance, the app then "flips" each bit of the result, one by one. For each flipped bit (`depth`), it calculates a new Target Gematria (`Main_Result ^ 2^depth`) and finds corresponding phrases. This reveals concepts that are numerologically "close" to the main result.
271
+ 5. **Scoring:** Results are sorted by a relevance score calculated as `Frequency / Word_Count` to prioritize short, common phrases.
272
+
273
+ ### Parameters
274
+ - **Verses to Process:** Limits how many verses the script analyzes. Higher numbers take longer.
275
+ - **Results per Resonance:** Limits how many phrases are shown for the main resonance and each variation.
276
+ - **Bitplane Variation Depth:** Controls how many "bit-flips" are tested. A depth of 5 will test flipping Bit 1, Bit 2, Bit 3, Bit 4, and Bit 5.
277
+ """
278
+ )
279
+
280
+ run_button.click(
281
+ fn=run_analysis,
282
+ inputs=[query, translate, process_verses, results_per_verse, xor_depth],
283
+ outputs=[output_markdown]
284
+ )
285
 
 
286
  if __name__ == "__main__":
287
+ if phrase_dictionary is None:
288
+ print("CRITICAL: Phrase dictionary could not be loaded. The application cannot start.")
289
+ print("Please ensure 'tanakh_phrasedict.cache' exists and is valid. Run 'build_indices.py' if necessary.")
290
+ else:
291
+ # The share=True argument creates a public link for easy sharing. Remove it if you only want local access.
292
+ demo.launch()