Download scripts/patch_generator_ui.py from wuhp/ghtest: direct link, hf CLI and curl.
- Browser
- Download file 7.31 kB
-
https://huggingface.co/spaces/wuhp/ghtest/resolve/main/scripts/patch_generator_ui.py
- Command line
-
hf download hf://spaces/wuhp/ghtest/scripts/patch_generator_ui.py
-
curl -L -o patch_generator_ui.py https://huggingface.co/spaces/wuhp/ghtest/resolve/main/scripts/patch_generator_ui.py
7.31 kB
| from pathlib import Path | |
| app_path = Path("app.py") | |
| app = app_path.read_text(encoding="utf-8") | |
| import_marker = "from voynich_lab.currier_report import build_currier_report\n" | |
| import_block = ( | |
| "from voynich_lab.currier_report import build_currier_report\n" | |
| "from voynich_lab.generator_adapters import SELFCITATION_ADAPTER_NAME, selfcitation_reference_matched\n" | |
| "from voynich_lab.generators import generate_naibbe\n" | |
| "from voynich_lab.selfcitation import SelfCitationConfig\n" | |
| "from voynich_lab.selfcitation_generator import generate_selfcitation\n" | |
| ) | |
| assert app.count(import_marker) == 1, "app import marker drifted" | |
| app = app.replace(import_marker, import_block, 1) | |
| function_marker = "# Every generator exposed to scorecard/discriminator obeys the same\n" | |
| function_block = '''def run_naibbe_generator_ui(plaintext: str, seed: int): | |
| if not plaintext.strip(): | |
| raise gr.Error("Naibbe requires meaningful plaintext input.") | |
| result = generate_naibbe(plaintext, seed=int(seed)) | |
| return ( | |
| result.ciphertext, | |
| result.canonical_ciphertext, | |
| result.respaced_plaintext, | |
| json.dumps(result.provenance, indent=2, sort_keys=True), | |
| ) | |
| def run_selfcitation_generator_ui(lines: int, seed: int): | |
| line_count = int(lines) | |
| config = SelfCitationConfig(lines_to_create=line_count, random_seed=int(seed)) | |
| result = generate_selfcitation(config, lines_to_create=line_count) | |
| summary = { | |
| "generated_lines": len(result.lines), | |
| "generated_characters": len(result.text), | |
| "seed": int(seed), | |
| "provenance": result.provenance, | |
| } | |
| return result.text, json.dumps(summary, indent=2, sort_keys=True) | |
| ''' | |
| assert app.count(function_marker) == 1, "function insertion marker drifted" | |
| app = app.replace(function_marker, function_block + function_marker, 1) | |
| choice_marker = ( | |
| ' "N6 position-conditioned Markov": lambda t, seed: ' | |
| 'position_conditioned_markov_surrogate(t, n_bins=10, seed=seed),\n}' | |
| ) | |
| choice_replacement = ( | |
| ' "N6 position-conditioned Markov": lambda t, seed: ' | |
| 'position_conditioned_markov_surrogate(t, n_bins=10, seed=seed),\n' | |
| ' SELFCITATION_ADAPTER_NAME: selfcitation_reference_matched,\n' | |
| '}' | |
| ) | |
| assert app.count(choice_marker) == 1, "generator choice marker drifted" | |
| app = app.replace(choice_marker, choice_replacement, 1) | |
| tab_marker = ' with gr.Tab("9 · Optional ZeroGPU probe"):\n' | |
| generator_tab = ''' with gr.Tab("9 · Generator baselines"): | |
| gr.Markdown( | |
| "Validated hypothesis generators are kept separate from the N0–N6 null ladder. " | |
| "Naibbe consumes meaningful plaintext; self-citation generates meaningless-but-structured pseudotext." | |
| ) | |
| with gr.Tab("Self-citation pseudotext"): | |
| with gr.Row(): | |
| sc_gen_lines = gr.Slider(2, 1200, value=120, step=1, label="Lines to generate") | |
| sc_gen_seed = gr.Number(value=19, precision=0, label="Pseudo-RNG seed") | |
| sc_gen_btn = gr.Button("Generate self-citation baseline", variant="primary") | |
| sc_gen_text = gr.Textbox(label="Generated pseudotext", lines=14, interactive=False) | |
| sc_gen_meta = gr.Code(label="Generation provenance", language="json") | |
| sc_gen_btn.click( | |
| run_selfcitation_generator_ui, | |
| [sc_gen_lines, sc_gen_seed], | |
| [sc_gen_text, sc_gen_meta], | |
| ) | |
| gr.Markdown( | |
| "The adversarial-validation dropdown also includes a size-matched self-citation adapter. " | |
| "That adapter changes only the pseudo-RNG seed and requested line count; all other released settings remain canonical." | |
| ) | |
| with gr.Tab("Naibbe meaningful cipher"): | |
| naibbe_plaintext = gr.Textbox( | |
| label="Meaningful plaintext", | |
| lines=8, | |
| placeholder="Paste Latin, Italian, or other alphabetic plaintext to encrypt…", | |
| ) | |
| naibbe_seed = gr.Number(value=0, precision=0, label="Seed") | |
| naibbe_btn = gr.Button("Generate Naibbe baseline") | |
| naibbe_cipher = gr.Textbox(label="Final ciphertext (3% output-space removal)", lines=10, interactive=False) | |
| naibbe_canonical = gr.Textbox(label="Canonical ciphertext before output-space removal", lines=10, interactive=False) | |
| naibbe_respaced = gr.Textbox(label="Respaced plaintext n-grams", lines=8, interactive=False) | |
| naibbe_meta = gr.Code(label="Generation provenance", language="json") | |
| naibbe_btn.click( | |
| run_naibbe_generator_ui, | |
| [naibbe_plaintext, naibbe_seed], | |
| [naibbe_cipher, naibbe_canonical, naibbe_respaced, naibbe_meta], | |
| ) | |
| ''' | |
| assert app.count(tab_marker) == 1, "tab insertion marker drifted" | |
| app = app.replace(tab_marker, generator_tab + ' with gr.Tab("10 · Optional ZeroGPU probe"):\n', 1) | |
| hf_marker = ' with gr.Tab("10 · Hugging Face sync"):\n' | |
| assert app.count(hf_marker) == 1, "HF tab marker drifted" | |
| app = app.replace(hf_marker, ' with gr.Tab("11 · Hugging Face sync"):\n', 1) | |
| app_path.write_text(app, encoding="utf-8") | |
| readme_path = Path("README.md") | |
| readme = readme_path.read_text(encoding="utf-8") | |
| naibbe_bullet = '- **Naibbe meaningful-cipher baseline** (`generators.py`): the paper-facing 52-card `naibbe.py` algorithm, exact 414-row substitution table, isolated seeded RNG, and provenance metadata. CI compares seeded plaintext respacing, canonical ciphertext, final 3%-space-dropped ciphertext, and ambiguity retry count directly against the pinned original implementation.\n' | |
| selfcitation_bullet = '- **Timm/Schinner self-citation pseudotext baseline** (`selfcitation_*.py`): the released Java generator is ported through RNG, glyph parsing, can-follow rules, source choice, statistics, slim morphing, and full generator orchestration. Dedicated CI gates compare the Python port against the pinned upstream Java implementation.\n' | |
| assert readme.count(naibbe_bullet) == 1, "README Naibbe bullet drifted" | |
| if selfcitation_bullet not in readme: | |
| readme = readme.replace(naibbe_bullet, naibbe_bullet + selfcitation_bullet, 1) | |
| old_gap = "1. **Generator library.** The paper-facing Naibbe 52-card baseline is implemented and source-equivalence-checked, and it remains explicitly classified as a meaningful-plaintext cipher rather than a null surrogate. The remaining generator gaps are the Timm/Schinner self-citation pseudotext family and a reproducible Rugg-style grille-cipher implementation; for both, prefer original authors' released code/data over prose-only approximations and preserve the meaningful-cipher versus meaningless-pseudotext distinction.\n" | |
| new_gap = "1. **Generator library.** The paper-facing Naibbe 52-card meaningful-cipher baseline and the Timm/Schinner meaningless self-citation pseudotext family are both implemented and source-equivalence-checked. The remaining major generator gap is a reproducible Rugg-style grille-cipher implementation sourced from original released code/data rather than a prose-only approximation.\n" | |
| assert readme.count(old_gap) == 1, "README generator-gap marker drifted" | |
| readme = readme.replace(old_gap, new_gap, 1) | |
| readme_path.write_text(readme, encoding="utf-8") | |