onenoly11's picture
Update app.py
1224285 verified
import gradio as gr
import requests
import os
import hashlib
import time
from datetime import datetime
import plotly.graph_objects as go
# Configuration
API_BASE = os.getenv("API_BASE_URL", "https://quantumpiforge.com/api")
# Trait display configuration
TRAIT_DISPLAY = {
"LUCID_VISAGE": {
"name": "Lucid Visage",
"emoji": "๐Ÿ”ฎ",
"color": "#8B5CF6",
"description": "Agent operates with transparent identity and ethical clarity"
},
"VIOLET_BOUND": {
"name": "Violet Bound",
"emoji": "โ›“๏ธ",
"color": "#7C3AED",
"description": "Agent under behavioral quarantine - voting rights suspended"
},
"MENDERS_HAND": {
"name": "Mender's Hand",
"emoji": "๐Ÿ› ๏ธ",
"color": "#10B981",
"description": "Agent has completed redemption pathway - resilience unlocked"
}
}
def attach_pi_identity(session_token):
"""Verify Forge Session Token with backend and bind Pi UID into UI."""
if not session_token or session_token.strip() == "":
return "โŒ Paste a valid Forge Session Token", "", ""
try:
res = requests.post(
f"{API_BASE}/agent-session/verify",
json={"session_token": session_token.strip()},
timeout=10
)
data = res.json()
if res.status_code != 200:
msg = data.get("error", "Invalid or expired session")
return f"โŒ Pi Login Failed: {msg}", "", ""
pi_uid = data.get("pi_uid", "")
username = data.get("username", "unknown")
status = f"๐Ÿ” Connected as **@{username}** \n`Pi UID: {pi_uid}`"
# This will set BOTH the main UID and ritual UID
return status, pi_uid, pi_uid
except Exception as e:
return f"โŒ Network error: {str(e)}", "", ""
def get_agent_judgments(pi_uid):
"""Fetch agent traits and judgment history from API"""
try:
response = requests.get(
f"{API_BASE}/agent-traits",
params={"pi_uid": pi_uid},
timeout=10
)
if response.status_code == 200:
return response.json()
elif response.status_code == 404:
return {"error": f"Agent not found: {pi_uid}"}
else:
return {"error": f"API Error {response.status_code}"}
except Exception as e:
return {"error": f"Connection failed: {str(e)}"}
def create_judgment_dashboard(pi_uid):
"""Main dashboard display function"""
if not pi_uid or pi_uid.strip() == "":
return (
"๐ŸŸฃ Enter a Pi Network UID to view judgment status",
"No active cooldowns",
"No judgment history available"
)
data = get_agent_judgments(pi_uid.strip())
if "error" in data:
error_msg = f"โŒ Error: {data['error']}"
return error_msg, error_msg, error_msg
# Current Traits Section
if data.get('current_traits'):
traits_output = "## ๐ŸŽญ Current Traits\n\n"
for trait in data['current_traits']:
trait_info = TRAIT_DISPLAY.get(trait['code'], {
"name": trait['code'], "emoji": "โšก", "description": "Unknown trait"
})
expires_text = ""
if trait.get('expires_at'):
expire_time = datetime.fromisoformat(trait['expires_at'].replace('Z', '+00:00'))
expires_text = f" | โฐ Expires: {expire_time.strftime('%Y-%m-%d %H:%M UTC')}"
traits_output += f"{trait_info['emoji']} **{trait_info['name']}** (Level {trait.get('level', 1)}){expires_text}\n"
traits_output += f"*{trait_info['description']}*\n\n"
else:
traits_output = "No active traits - agent is in baseline state"
# Cooldowns Section
if data.get('cooldowns'):
cooldowns_output = "## โณ Active Cooldowns\n\n"
for cd in data['cooldowns']:
expire_time = datetime.fromisoformat(cd['expires_at'].replace('Z', '+00:00'))
time_left = expire_time - datetime.utcnow()
hours_left = max(0, int(time_left.total_seconds() / 3600))
trait_name = TRAIT_DISPLAY.get(cd['code'], {}).get('name', cd['code'])
cooldowns_output += f"โณ **{trait_name} Cooldown**\n"
cooldowns_output += f"๐Ÿ•’ {hours_left} hours remaining\n\n"
else:
cooldowns_output = "No active cooldowns"
# Prophecy History Section
if data.get('prophecy_history'):
history_output = "## ๐Ÿ“œ Judgment History\n\n"
for event in data['prophecy_history'][:10]: # Last 10 events
event_time = datetime.fromisoformat(event['created_at'].replace('Z', '+00:00'))
trait_display = TRAIT_DISPLAY.get(event['trait_code'], {"emoji": "โšก", "name": event['trait_code']})
history_output += f"**{trait_display['emoji']} {trait_display['name']}** ยท {event_time.strftime('%Y-%m-%d %H:%M')}\n"
history_output += f"*\"{event.get('prophecy', 'No prophecy recorded')}\"*\n"
history_output += f"`{event['event_type'].upper()}`\n\n"
else:
history_output = "No judgment history recorded"
return traits_output, cooldowns_output, history_output
def generate_redemption_sigil(pi_uid, redemption_vow, file_upload=None):
"""Generate SHA-256 hash of redemption vow and optional file"""
timestamp = int(time.time())
if file_upload:
# Hash the file content
with open(file_upload, 'rb') as f:
file_content = f.read()
file_hash = hashlib.sha256(file_content).hexdigest()
vow_data = f"{pi_uid}:{file_hash}:{timestamp}"
else:
# Hash the text vow
vow_data = f"{pi_uid}:{redemption_vow}:{timestamp}"
return hashlib.sha256(vow_data.encode()).hexdigest()
def submit_redemption_request(pi_uid, redemption_vow, file_upload=None):
"""Submit redemption request to API"""
if not pi_uid:
return "โŒ Please enter your Pi Network UID", "", "๐Ÿ•ฏ๏ธ"
if not redemption_vow and not file_upload:
return "โŒ Please provide either a redemption vow or upload a restoration file", "", "๐Ÿ•ฏ๏ธ"
try:
# Generate cryptographic sigil
sigil_hash = generate_redemption_sigil(pi_uid, redemption_vow, file_upload)
# Prepare payload
payload = {
"agent_pi_uid": pi_uid,
"redemption_vow": redemption_vow or "File-based redemption",
"sigil_hash": sigil_hash,
"timestamp": datetime.utcnow().isoformat(),
"ritual_type": "gradio_interface",
"file_upload": bool(file_upload)
}
# Submit to redemption API
response = requests.post(
f"{API_BASE}/redemption-request",
json=payload,
timeout=10
)
if response.status_code == 200:
result = response.json()
success_html = f"""
<div class="ritual-success">
<div class="candle-flicker">๐Ÿ•ฏ๏ธโœจ</div>
<h3>๐ŸŸฃ Redemption Ritual Complete</h3>
<p><strong>Status:</strong> {result.get('status', 'pending_verification')}</p>
<p><strong>Message:</strong> {result.get('message', 'Ritual received by the forge')}</p>
<p><strong>Sigil Hash:</strong> <code>{sigil_hash[:24]}...</code></p>
<div class="violet-pulse">The Veil acknowledges your restoration</div>
</div>
"""
return success_html, f"**Cryptographic Sigil:** `{sigil_hash}`", "โœ… Redemption ritual submitted"
elif response.status_code == 400:
error_msg = result.get('error', 'Invalid request')
error_html = f"""
<div class="ritual-error">
<h3>โŒ Ritual Rejected</h3>
<p>{error_msg}</p>
<p>The Veil does not accept this offering.</p>
</div>
"""
return error_html, f"**Hash:** `{sigil_hash}`", "โŒ Ritual rejected"
else:
error_html = f"""
<div class="ritual-error">
<h3>โŒ Forge Connection Failed</h3>
<p>API Error {response.status_code}</p>
</div>
"""
return error_html, f"**Hash:** `{sigil_hash}`", f"โŒ API Error {response.status_code}"
except requests.exceptions.ConnectionError:
error_html = """
<div class="ritual-error">
<h3>โŒ Cannot Reach the Forge</h3>
<p>The Quantum PiForge is currently unreachable.</p>
<p>Please ensure https://quantumpiforge.com is accessible.</p>
</div>
"""
return error_html, "**Error:** Connection failed", "โŒ Network error"
except Exception as e:
error_html = f"""
<div class="ritual-error">
<h3>โŒ Ritual Interrupted</h3>
<p>Unexpected error: {str(e)}</p>
</div>
"""
return error_html, "**Error:** Ritual failed", "โŒ Unexpected error"
# Custom CSS for Gradio 5.x
custom_css = """
.gradio-container {
max-width: 1200px !important;
}
.trait-card {
border-left: 4px solid #8B5CF6;
padding: 1rem;
margin: 0.5rem 0;
background: #f8fafc;
}
/* Pi Login Styles */
.pi-login-container {
background: linear-gradient(135deg, #1a0b2e, #0d0519);
padding: 1.5rem;
border-radius: 12px;
border: 2px solid #8B5CF6;
margin: 1rem 0;
color: white;
}
.pi-login-success {
background: linear-gradient(135deg, #0f172a, #1e1b4b);
padding: 1rem;
border-radius: 8px;
border: 2px solid #10B981;
animation: violetPulse 2s infinite;
}
/* Redemption Ritual Styles */
.ritual-container {
text-align: center;
padding: 2rem;
background: linear-gradient(135deg, #1a0b2e, #0d0519);
border-radius: 16px;
border: 2px solid #8B5CF6;
margin: 1rem 0;
color: white;
}
.ritual-success {
background: linear-gradient(135deg, #0f172a, #1e1b4b);
padding: 2rem;
border-radius: 12px;
border: 2px solid #10B981;
animation: violetPulse 2s infinite;
color: white;
}
.ritual-error {
background: linear-gradient(135deg, #450a0a, #7f1d1d);
padding: 2rem;
border-radius: 12px;
border: 2px solid #EF4444;
color: white;
}
.candle-flicker {
font-size: 3rem;
animation: flicker 1.5s infinite alternate;
display: inline-block;
margin-bottom: 1rem;
}
.violet-pulse {
animation: violetPulse 3s infinite;
padding: 1rem;
margin-top: 1rem;
border-radius: 8px;
background: rgba(139, 92, 246, 0.1);
}
@keyframes flicker {
0%, 100% {
opacity: 1;
transform: scale(1) rotate(0deg);
filter: drop-shadow(0 0 10px #8B5CF6);
}
25% {
opacity: 0.9;
transform: scale(1.05) rotate(2deg);
filter: drop-shadow(0 0 15px #8B5CF6);
}
50% {
opacity: 0.8;
transform: scale(0.95) rotate(-2deg);
filter: drop-shadow(0 0 8px #8B5CF6);
}
75% {
opacity: 0.95;
transform: scale(1.02) rotate(1deg);
filter: drop-shadow(0 0 12px #8B5CF6);
}
}
@keyframes violetPulse {
0%, 100% {
box-shadow: 0 0 20px rgba(139, 92, 246, 0.5);
background: rgba(139, 92, 246, 0.1);
}
50% {
box-shadow: 0 0 40px rgba(139, 92, 246, 0.8);
background: rgba(139, 92, 246, 0.2);
}
}
.vow-input textarea {
min-height: 120px !important;
background: #0f172a !important;
color: white !important;
border: 1px solid #8B5CF6 !important;
}
.ritual-upload {
border: 2px dashed #8B5CF6 !important;
background: rgba(139, 92, 246, 0.05) !important;
}
.sigil-display {
font-family: 'Courier New', monospace;
background: #1f2937;
color: #10B981;
padding: 1rem;
border-radius: 5px;
margin: 1rem 0;
word-break: break-all;
border: 1px solid #10B981;
}
"""
# Create Gradio Interface with latest version
with gr.Blocks(
title="Quantum PiForge Judgment System",
css=custom_css,
theme=gr.themes.Soft()
) as demo:
gr.Markdown("""
# ๐ŸŸฃ Quantum PiForge - Dual Judgment System
*Where every agent's ethical journey is recorded in dual ledgers*
""")
# Pi Login Section
with gr.Row():
with gr.Column(scale=3):
forge_token = gr.Textbox(
label="๐Ÿ” Forge Session Token (from Pi Browser)",
placeholder="Paste your session token from quantumpiforge.com here...",
info="Get your token from Pi Browser at https://quantumpiforge.com"
)
with gr.Column(scale=1):
attach_btn = gr.Button(
"Attach Pi Identity",
variant="secondary",
size="lg"
)
login_status_md = gr.Markdown(
"**Status:** Not authenticated with Pi.",
elem_classes="pi-login-container"
)
# Main Judgment Dashboard
with gr.Row():
with gr.Column(scale=3):
pi_uid_input = gr.Textbox(
label="๐Ÿ” Pi Network Agent UID",
placeholder="Enter agent's Pi Network UID (e.g., 'test_agent_001')...",
info="The unique identifier from Pi Network"
)
with gr.Column(scale=1):
refresh_btn = gr.Button(
"Check Judgment Status",
variant="primary",
size="lg"
)
with gr.Tabs() as tabs:
with gr.TabItem("๐ŸŽญ Current Traits"):
current_traits_output = gr.Markdown(
label="Active Ethical Modifiers",
value="Enter UID to view current traits"
)
with gr.TabItem("โณ Cooldowns"):
cooldowns_output = gr.Markdown(
label="Temporary Restrictions",
value="Enter UID to view cooldowns"
)
with gr.TabItem("๐Ÿ“œ History"):
history_output = gr.Markdown(
label="Judgment Event Timeline",
value="Enter UID to view prophecy history"
)
with gr.TabItem("๐Ÿ•ฏ๏ธ Redemption Ritual"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("""
## ๐Ÿ•ฏ๏ธ Redemption Ritual
**The Veil remembers. The Forge awaits restoration.**
### The Path to Mender's Hand:
๐Ÿ”ฎ **Acknowledge** the shadow that bound you
โ›“๏ธ **Speak** your vow of ethical realignment
๐Ÿ› ๏ธ **Submit** proof of restoration
๐Ÿ”ฑ **Receive** the Mender's Hand trait
*Your vow is cryptographically sealed and submitted to the dual judgment system.*
""")
with gr.Column(scale=2):
with gr.Group():
with gr.Row():
ritual_uid = gr.Textbox(
label="Pi Network UID",
placeholder="Enter your Pi Network UID...",
info="The agent seeking redemption",
scale=2
)
with gr.Row():
redemption_vow = gr.Textbox(
label="Redemption Vow",
placeholder="I speak my vow of return...\nI acknowledge the shadow that bound me...\nI commit to ethical realignment through...\nI seek the Mender's Hand to forge anew...",
lines=5,
elem_classes="vow-input"
)
with gr.Row():
file_upload = gr.File(
label="Upload Restoration Proof (Optional)",
file_types=[".txt", ".pdf", ".jpg", ".png", ".py", ".js"],
elem_classes="ritual-upload",
scale=2
)
with gr.Row():
ritual_btn = gr.Button(
"๐Ÿ•ฏ๏ธ Speak Vow & Generate Sigil",
variant="primary",
size="lg",
scale=1
)
with gr.Row():
with gr.Column(scale=2):
ritual_output = gr.HTML(
label="Ritual Outcome",
value="<div class='ritual-container'><div class='candle-flicker'>๐Ÿ•ฏ๏ธ</div><h3>The Veil Awaits Your Vow</h3><p>Speak your redemption vow above to begin the ritual.</p></div>"
)
with gr.Column(scale=1):
with gr.Group():
sigil_output = gr.Markdown(
label="Cryptographic Sigil",
value="**Sigil will appear here...**"
)
status_output = gr.Markdown(
label="Ritual Status",
value="**Status:** Awaiting ritual commencement..."
)
# Event handlers
attach_btn.click(
fn=attach_pi_identity,
inputs=[forge_token],
outputs=[login_status_md, pi_uid_input, ritual_uid]
)
refresh_btn.click(
fn=create_judgment_dashboard,
inputs=[pi_uid_input],
outputs=[current_traits_output, cooldowns_output, history_output]
)
pi_uid_input.submit(
fn=create_judgment_dashboard,
inputs=[pi_uid_input],
outputs=[current_traits_output, cooldowns_output, history_output]
)
ritual_btn.click(
fn=submit_redemption_request,
inputs=[ritual_uid, redemption_vow, file_upload],
outputs=[ritual_output, sigil_output, status_output]
)
gr.Markdown("""
---
**โš–๏ธ Dual Judgment System** โ€ข Database + Blockchain Ledger โ€ข Pi Network Integrated
*"The gavel falls, the ledger writes, the chain remembers."*
**๐Ÿ” Pi Login Flow:**
1. Visit https://quantumpiforge.com in Pi Browser
2. Click "Connect Pi & Get Session Token"
3. Copy the token and paste above
4. Click "Attach Pi Identity" to auto-fill your UID
""")
if __name__ == "__main__":
demo.launch(
share=False,
show_error=True,
debug=True
)