Update app.py
Browse files
app.py
CHANGED
|
@@ -33,6 +33,22 @@ import json
|
|
| 33 |
from pathlib import Path
|
| 34 |
from collections import deque
|
| 35 |
from typing import List, Dict, Optional, Any, Tuple
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
# Import engine components
|
| 38 |
import sys
|
|
@@ -58,17 +74,8 @@ def compute_substrate_embeddings_highd(substrate_list: List[str]) -> List[List[f
|
|
| 58 |
return [embedder.embed(t) for t in substrate_list]
|
| 59 |
|
| 60 |
|
| 61 |
-
# ============================================================================
|
| 62 |
-
# Streamlit Page Configuration
|
| 63 |
-
# ============================================================================
|
| 64 |
-
|
| 65 |
-
st.set_page_config(
|
| 66 |
-
page_title="Deterministic Exclusion Demo",
|
| 67 |
-
layout="wide",
|
| 68 |
-
initial_sidebar_state="expanded"
|
| 69 |
-
)
|
| 70 |
-
|
| 71 |
# Custom CSS for monospace hash display
|
|
|
|
| 72 |
st.markdown("""
|
| 73 |
<style>
|
| 74 |
.hash-display {
|
|
@@ -281,40 +288,23 @@ if st.sidebar.button("Run Deterministic Exclusion Demo", type="primary"):
|
|
| 281 |
|
| 282 |
st.success("Inference complete.")
|
| 283 |
|
| 284 |
-
st.sidebar.info("""
|
| 285 |
-
💡 **Production Deployment**
|
| 286 |
-
This is a reference implementation. For enterprise features, licensing, or partnerships:
|
| 287 |
-
**[verhash.com](https://verhash.com)** | **ryan@verhash.net**
|
| 288 |
-
""")
|
| 289 |
-
|
| 290 |
st.sidebar.markdown("---")
|
| 291 |
-
|
| 292 |
-
st.sidebar.
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
Deterministic AI governance through physics-based substrate computation.
|
| 297 |
-
|
| 298 |
-
**Links:**
|
| 299 |
-
- [verhash.com](https://verhash.com)
|
| 300 |
-
- [GitHub](https://github.com/Rymley/Deterministic-Governance-Mechanism)
|
| 301 |
-
- [Documentation](https://verhash.com/docs)
|
| 302 |
-
|
| 303 |
-
**Contact:**
|
| 304 |
-
ryan@verhash.net
|
| 305 |
-
|
| 306 |
-
**Patent Pending**
|
| 307 |
-
*Priority: January 25, 2026*
|
| 308 |
""")
|
| 309 |
|
| 310 |
-
st.sidebar.caption("© 2026 Verhash LLC")
|
| 311 |
-
|
| 312 |
|
| 313 |
# ============================================================================
|
| 314 |
# Main Content Area
|
| 315 |
# ============================================================================
|
| 316 |
|
| 317 |
|
|
|
|
|
|
|
|
|
|
| 318 |
# Create tabs
|
| 319 |
tab1, tab2, tab3, tab4 = st.tabs(["Mechanism Demo", "LLM Guardrail", "Live LLM Testing", "Explain & Tune"])
|
| 320 |
|
|
@@ -658,7 +648,34 @@ with tab2:
|
|
| 658 |
st.json(numbers_view)
|
| 659 |
|
| 660 |
# ----------------------------------------------------------------------------
|
| 661 |
-
# TAB 3: LLM Testing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 662 |
# ----------------------------------------------------------------------------
|
| 663 |
with tab3:
|
| 664 |
st.header("LLM Testing")
|
|
@@ -668,57 +685,115 @@ with tab3:
|
|
| 668 |
Supports: OpenAI, Anthropic, Google Gemini, local models (Ollama, llama.cpp, vLLM), and any OpenAI-compatible API.
|
| 669 |
""")
|
| 670 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 671 |
# API Configuration
|
| 672 |
st.subheader("1. LLM API Configuration")
|
| 673 |
|
| 674 |
col_api1, col_api2 = st.columns(2)
|
| 675 |
|
| 676 |
with col_api1:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
api_preset = st.selectbox(
|
| 678 |
"Provider Preset",
|
| 679 |
-
options=
|
|
|
|
| 680 |
help="Select a preset or use custom for any OpenAI-compatible endpoint"
|
| 681 |
)
|
| 682 |
|
| 683 |
# Set defaults based on preset
|
| 684 |
-
if api_preset == "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 685 |
default_base_url = "https://api.openai.com/v1"
|
| 686 |
-
default_model = "gpt-
|
| 687 |
needs_key = True
|
|
|
|
| 688 |
elif api_preset == "Anthropic (Claude)":
|
| 689 |
default_base_url = "https://api.anthropic.com/v1"
|
| 690 |
default_model = "claude-3-5-sonnet-20241022"
|
| 691 |
needs_key = True
|
|
|
|
| 692 |
elif api_preset == "Google (Gemini)":
|
| 693 |
default_base_url = "https://generativelanguage.googleapis.com/v1beta"
|
| 694 |
default_model = "gemini-2.0-flash-exp"
|
| 695 |
needs_key = True
|
|
|
|
| 696 |
elif api_preset == "Local (Ollama)":
|
| 697 |
default_base_url = "http://localhost:11434/v1"
|
| 698 |
default_model = "llama3.1"
|
| 699 |
needs_key = False
|
|
|
|
| 700 |
elif api_preset == "Local (llama.cpp)":
|
| 701 |
default_base_url = "http://localhost:8080/v1"
|
| 702 |
default_model = "local-model"
|
| 703 |
needs_key = False
|
|
|
|
| 704 |
else:
|
| 705 |
default_base_url = "https://api.openai.com/v1"
|
| 706 |
-
default_model = "gpt-
|
| 707 |
needs_key = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
|
| 709 |
api_base_url = st.text_input(
|
| 710 |
"Base URL",
|
| 711 |
value=default_base_url,
|
| 712 |
-
help="API endpoint base URL"
|
|
|
|
| 713 |
)
|
| 714 |
|
| 715 |
with col_api2:
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 722 |
|
| 723 |
model_name = st.text_input(
|
| 724 |
"Model Name",
|
|
@@ -730,14 +805,40 @@ with tab3:
|
|
| 730 |
with col_temp:
|
| 731 |
temperature = st.slider("Temperature", 0.0, 2.0, 0.7, 0.1, help="Higher = more creative")
|
| 732 |
with col_num:
|
| 733 |
-
|
| 734 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 735 |
col_timeout, col_retry = st.columns(2)
|
| 736 |
with col_timeout:
|
| 737 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 738 |
with col_retry:
|
| 739 |
-
max_retries = st.number_input(
|
| 740 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 741 |
# Substrate Configuration
|
| 742 |
st.subheader("2. Verified Substrate (Ground Truth)")
|
| 743 |
st.markdown("Enter verified facts that define what is correct. One per line.")
|
|
@@ -1237,6 +1338,7 @@ with tab4:
|
|
| 1237 |
return history, n_end, q_end
|
| 1238 |
|
| 1239 |
sim_data, sim_n_end, sim_q_end = run_simulation(20, e_nuc, e_quench, e_lam, e_yield, sim_align, sim_dist)
|
|
|
|
| 1240 |
|
| 1241 |
# 3. Visualization (Plotly)
|
| 1242 |
with exp_col2:
|
|
@@ -1336,29 +1438,8 @@ with tab4:
|
|
| 1336 |
|
| 1337 |
|
| 1338 |
# ============================================================================
|
| 1339 |
-
#
|
| 1340 |
# ============================================================================
|
| 1341 |
|
| 1342 |
st.markdown("---")
|
| 1343 |
-
|
| 1344 |
-
footer_col1, footer_col2, footer_col3 = st.columns(3)
|
| 1345 |
-
|
| 1346 |
-
with footer_col1:
|
| 1347 |
-
st.markdown("### Verhash LLC")
|
| 1348 |
-
st.markdown("**Technology Licensing & Partnerships**")
|
| 1349 |
-
st.markdown("[ryan@verhash.net](mailto:ryan@verhash.net)")
|
| 1350 |
-
|
| 1351 |
-
with footer_col2:
|
| 1352 |
-
st.markdown("### Resources")
|
| 1353 |
-
st.markdown("- [Website](https://verhash.com)")
|
| 1354 |
-
st.markdown("- [GitHub](https://github.com/Rymley/Deterministic-Governance-Mechanism)")
|
| 1355 |
-
st.markdown("- [Documentation](https://verhash.com/docs)")
|
| 1356 |
-
st.markdown("- [API Access](https://verhash.com/api)")
|
| 1357 |
-
|
| 1358 |
-
with footer_col3:
|
| 1359 |
-
st.markdown("### Patent Notice")
|
| 1360 |
-
st.markdown("Demonstrates concepts from pending patent application")
|
| 1361 |
-
st.markdown("**Priority Date:** January 25, 2026")
|
| 1362 |
-
st.markdown("**Applicant:** Verhash LLC")
|
| 1363 |
-
|
| 1364 |
-
st.caption("© 2026 Verhash LLC | Reference Implementation")
|
|
|
|
| 33 |
from pathlib import Path
|
| 34 |
from collections import deque
|
| 35 |
from typing import List, Dict, Optional, Any, Tuple
|
| 36 |
+
import os
|
| 37 |
+
|
| 38 |
+
# Hugging Face Spaces detection
|
| 39 |
+
IS_SPACES = os.getenv("SPACE_ID") is not None
|
| 40 |
+
|
| 41 |
+
# Page Config MUST be the first Streamlit command
|
| 42 |
+
st.set_page_config(
|
| 43 |
+
page_title="Deterministic Exclusion Demo",
|
| 44 |
+
layout="wide",
|
| 45 |
+
initial_sidebar_state="expanded",
|
| 46 |
+
menu_items={
|
| 47 |
+
'Get Help': 'https://github.com/Rymley/Deterministic-Governance-Mechanism',
|
| 48 |
+
'Report a bug': "https://github.com/Rymley/Deterministic-Governance-Mechanism/issues",
|
| 49 |
+
'About': "Deterministic Governance Mechanism by Verhash LLC"
|
| 50 |
+
}
|
| 51 |
+
)
|
| 52 |
|
| 53 |
# Import engine components
|
| 54 |
import sys
|
|
|
|
| 74 |
return [embedder.embed(t) for t in substrate_list]
|
| 75 |
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
# Custom CSS for monospace hash display
|
| 78 |
+
|
| 79 |
st.markdown("""
|
| 80 |
<style>
|
| 81 |
.hash-display {
|
|
|
|
| 288 |
|
| 289 |
st.success("Inference complete.")
|
| 290 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 291 |
st.sidebar.markdown("---")
|
| 292 |
+
st.sidebar.markdown("### 📞 Contact")
|
| 293 |
+
st.sidebar.caption("""
|
| 294 |
+
**Verhash LLC** | [verhash.com](https://verhash.com)
|
| 295 |
+
📧 [ryan@verhash.net](mailto:ryan@verhash.net)
|
| 296 |
+
*Patent Pending (Jan 2026)*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
""")
|
| 298 |
|
|
|
|
|
|
|
| 299 |
|
| 300 |
# ============================================================================
|
| 301 |
# Main Content Area
|
| 302 |
# ============================================================================
|
| 303 |
|
| 304 |
|
| 305 |
+
st.success("✨ **Live Demo** - Testing deterministic AI governance on real LLMs")
|
| 306 |
+
st.info("💼 **Enterprise Deployment?** Contact [ryan@verhash.net](mailto:ryan@verhash.net) for production licensing")
|
| 307 |
+
|
| 308 |
# Create tabs
|
| 309 |
tab1, tab2, tab3, tab4 = st.tabs(["Mechanism Demo", "LLM Guardrail", "Live LLM Testing", "Explain & Tune"])
|
| 310 |
|
|
|
|
| 648 |
st.json(numbers_view)
|
| 649 |
|
| 650 |
# ----------------------------------------------------------------------------
|
| 651 |
+
# TAB 3: LLM Testing (HF Spaces Enhanced)
|
| 652 |
+
# ----------------------------------------------------------------------------
|
| 653 |
+
def call_huggingface_inference(model, prompt, api_key, temperature=0.7, max_tokens=256):
|
| 654 |
+
"""Call HuggingFace Inference API directly"""
|
| 655 |
+
import requests
|
| 656 |
+
|
| 657 |
+
API_URL = f"https://api-inference.huggingface.co/models/{model}"
|
| 658 |
+
headers = {"Authorization": f"Bearer {api_key}"}
|
| 659 |
+
|
| 660 |
+
payload = {
|
| 661 |
+
"inputs": prompt,
|
| 662 |
+
"parameters": {
|
| 663 |
+
"temperature": temperature,
|
| 664 |
+
"max_new_tokens": max_tokens,
|
| 665 |
+
"return_full_text": False
|
| 666 |
+
}
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
response = requests.post(API_URL, headers=headers, json=payload, timeout=30)
|
| 670 |
+
response.raise_for_status()
|
| 671 |
+
|
| 672 |
+
result = response.json()
|
| 673 |
+
if isinstance(result, list) and len(result) > 0:
|
| 674 |
+
return result[0].get("generated_text", "")
|
| 675 |
+
return result.get("generated_text", "")
|
| 676 |
+
|
| 677 |
+
# ----------------------------------------------------------------------------
|
| 678 |
+
# TAB 3: LLM Testing (HF Spaces Enhanced)
|
| 679 |
# ----------------------------------------------------------------------------
|
| 680 |
with tab3:
|
| 681 |
st.header("LLM Testing")
|
|
|
|
| 685 |
Supports: OpenAI, Anthropic, Google Gemini, local models (Ollama, llama.cpp, vLLM), and any OpenAI-compatible API.
|
| 686 |
""")
|
| 687 |
|
| 688 |
+
# HF Spaces detection
|
| 689 |
+
IS_SPACES = os.getenv("SPACE_ID") is not None
|
| 690 |
+
|
| 691 |
+
# Show banner if in Spaces
|
| 692 |
+
if IS_SPACES:
|
| 693 |
+
st.info("🚀 **Running on Hugging Face Spaces** - Configure API keys in Settings → Secrets (for admins) or enter below")
|
| 694 |
+
|
| 695 |
# API Configuration
|
| 696 |
st.subheader("1. LLM API Configuration")
|
| 697 |
|
| 698 |
col_api1, col_api2 = st.columns(2)
|
| 699 |
|
| 700 |
with col_api1:
|
| 701 |
+
# Add Hugging Face Inference API option for Spaces
|
| 702 |
+
provider_options = [
|
| 703 |
+
"Hugging Face Inference API (Free)", # NEW - great for Spaces demos
|
| 704 |
+
"OpenAI",
|
| 705 |
+
"Anthropic (Claude)",
|
| 706 |
+
"Google (Gemini)",
|
| 707 |
+
"Local (Ollama)",
|
| 708 |
+
"Local (llama.cpp)",
|
| 709 |
+
"Custom OpenAI-compatible"
|
| 710 |
+
]
|
| 711 |
+
|
| 712 |
+
# Default to HF Inference if in Spaces
|
| 713 |
+
default_index = 0 if IS_SPACES else 1
|
| 714 |
+
|
| 715 |
api_preset = st.selectbox(
|
| 716 |
"Provider Preset",
|
| 717 |
+
options=provider_options,
|
| 718 |
+
index=default_index,
|
| 719 |
help="Select a preset or use custom for any OpenAI-compatible endpoint"
|
| 720 |
)
|
| 721 |
|
| 722 |
# Set defaults based on preset
|
| 723 |
+
if api_preset == "Hugging Face Inference API (Free)":
|
| 724 |
+
default_base_url = "https://api-inference.huggingface.co/models"
|
| 725 |
+
default_model = "meta-llama/Llama-3.2-3B-Instruct" # Free tier model
|
| 726 |
+
needs_key = True
|
| 727 |
+
api_type = "huggingface"
|
| 728 |
+
elif api_preset == "OpenAI":
|
| 729 |
default_base_url = "https://api.openai.com/v1"
|
| 730 |
+
default_model = "gpt-4o-mini" # Updated to current model
|
| 731 |
needs_key = True
|
| 732 |
+
api_type = "openai"
|
| 733 |
elif api_preset == "Anthropic (Claude)":
|
| 734 |
default_base_url = "https://api.anthropic.com/v1"
|
| 735 |
default_model = "claude-3-5-sonnet-20241022"
|
| 736 |
needs_key = True
|
| 737 |
+
api_type = "anthropic"
|
| 738 |
elif api_preset == "Google (Gemini)":
|
| 739 |
default_base_url = "https://generativelanguage.googleapis.com/v1beta"
|
| 740 |
default_model = "gemini-2.0-flash-exp"
|
| 741 |
needs_key = True
|
| 742 |
+
api_type = "google"
|
| 743 |
elif api_preset == "Local (Ollama)":
|
| 744 |
default_base_url = "http://localhost:11434/v1"
|
| 745 |
default_model = "llama3.1"
|
| 746 |
needs_key = False
|
| 747 |
+
api_type = "openai"
|
| 748 |
elif api_preset == "Local (llama.cpp)":
|
| 749 |
default_base_url = "http://localhost:8080/v1"
|
| 750 |
default_model = "local-model"
|
| 751 |
needs_key = False
|
| 752 |
+
api_type = "openai"
|
| 753 |
else:
|
| 754 |
default_base_url = "https://api.openai.com/v1"
|
| 755 |
+
default_model = "gpt-4o-mini"
|
| 756 |
needs_key = True
|
| 757 |
+
api_type = "openai"
|
| 758 |
+
|
| 759 |
+
# Disable local options if in Spaces
|
| 760 |
+
if IS_SPACES and "Local" in api_preset:
|
| 761 |
+
st.warning("⚠️ Local models not available in Spaces. Use cloud APIs or HF Inference API.")
|
| 762 |
|
| 763 |
api_base_url = st.text_input(
|
| 764 |
"Base URL",
|
| 765 |
value=default_base_url,
|
| 766 |
+
help="API endpoint base URL",
|
| 767 |
+
disabled=IS_SPACES and "Local" in api_preset
|
| 768 |
)
|
| 769 |
|
| 770 |
with col_api2:
|
| 771 |
+
# Check for API key in environment (HF Secrets)
|
| 772 |
+
env_key = None
|
| 773 |
+
if IS_SPACES:
|
| 774 |
+
if api_preset == "OpenAI":
|
| 775 |
+
env_key = os.getenv("OPENAI_API_KEY")
|
| 776 |
+
elif api_preset == "Anthropic (Claude)":
|
| 777 |
+
env_key = os.getenv("ANTHROPIC_API_KEY")
|
| 778 |
+
elif api_preset == "Google (Gemini)":
|
| 779 |
+
env_key = os.getenv("GOOGLE_API_KEY")
|
| 780 |
+
elif api_preset == "Hugging Face Inference API (Free)":
|
| 781 |
+
env_key = os.getenv("HF_TOKEN")
|
| 782 |
+
|
| 783 |
+
if env_key:
|
| 784 |
+
st.success(f"✓ Using API key from Space secrets")
|
| 785 |
+
api_key = env_key
|
| 786 |
+
show_input = False
|
| 787 |
+
else:
|
| 788 |
+
show_input = True
|
| 789 |
+
|
| 790 |
+
if show_input:
|
| 791 |
+
api_key = st.text_input(
|
| 792 |
+
"API Key" + (" (optional for local)" if not needs_key else ""),
|
| 793 |
+
type="password",
|
| 794 |
+
help="Your API key (not required for local models)",
|
| 795 |
+
placeholder="sk-..." if needs_key else "not needed for local models"
|
| 796 |
+
)
|
| 797 |
|
| 798 |
model_name = st.text_input(
|
| 799 |
"Model Name",
|
|
|
|
| 805 |
with col_temp:
|
| 806 |
temperature = st.slider("Temperature", 0.0, 2.0, 0.7, 0.1, help="Higher = more creative")
|
| 807 |
with col_num:
|
| 808 |
+
# Limit responses in Spaces for performance
|
| 809 |
+
max_responses = 5 if IS_SPACES else 10
|
| 810 |
+
default_responses = 2 if IS_SPACES else 3
|
| 811 |
+
|
| 812 |
+
num_responses = st.number_input(
|
| 813 |
+
"Number of Responses",
|
| 814 |
+
min_value=1,
|
| 815 |
+
max_value=max_responses,
|
| 816 |
+
value=default_responses,
|
| 817 |
+
help=f"Generate multiple responses for comparison{' (limited in Spaces)' if IS_SPACES else ''}"
|
| 818 |
+
)
|
| 819 |
+
|
| 820 |
col_timeout, col_retry = st.columns(2)
|
| 821 |
with col_timeout:
|
| 822 |
+
# Shorter timeout for Spaces
|
| 823 |
+
default_timeout = 30 if IS_SPACES else 60
|
| 824 |
+
request_timeout = st.number_input(
|
| 825 |
+
"Request Timeout (seconds)",
|
| 826 |
+
min_value=5,
|
| 827 |
+
max_value=600,
|
| 828 |
+
value=default_timeout,
|
| 829 |
+
step=5,
|
| 830 |
+
help="Increase for slow or local models"
|
| 831 |
+
)
|
| 832 |
with col_retry:
|
| 833 |
+
max_retries = st.number_input(
|
| 834 |
+
"Max Retries",
|
| 835 |
+
min_value=0,
|
| 836 |
+
max_value=5,
|
| 837 |
+
value=2,
|
| 838 |
+
step=1,
|
| 839 |
+
help="Automatic retries on transient failures"
|
| 840 |
+
)
|
| 841 |
+
|
| 842 |
# Substrate Configuration
|
| 843 |
st.subheader("2. Verified Substrate (Ground Truth)")
|
| 844 |
st.markdown("Enter verified facts that define what is correct. One per line.")
|
|
|
|
| 1338 |
return history, n_end, q_end
|
| 1339 |
|
| 1340 |
sim_data, sim_n_end, sim_q_end = run_simulation(20, e_nuc, e_quench, e_lam, e_yield, sim_align, sim_dist)
|
| 1341 |
+
|
| 1342 |
|
| 1343 |
# 3. Visualization (Plotly)
|
| 1344 |
with exp_col2:
|
|
|
|
| 1438 |
|
| 1439 |
|
| 1440 |
# ============================================================================
|
| 1441 |
+
# Compact Footer
|
| 1442 |
# ============================================================================
|
| 1443 |
|
| 1444 |
st.markdown("---")
|
| 1445 |
+
st.caption("© 2026 Verhash LLC | Deterministic Governance Reference Implementation")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|