onenoly11 commited on
Commit
1224285
ยท
verified ยท
1 Parent(s): 9e10ef5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +516 -319
app.py CHANGED
@@ -1,353 +1,550 @@
1
  import gradio as gr
2
- import hashlib
3
  import requests
4
- from typing import Optional, Tuple, Any
5
-
6
- # ๐Ÿ”— Your backend base URL (update if needed)
7
- API_BASE_URL = "https://quantumpiforge.com"
8
-
9
- # ๐ŸŽจ Custom CSS for candle flicker & violet pulse
10
- VEIL_CSS = """
11
- .veil-widget {
12
- margin-top: 24px;
13
- padding: 20px;
14
- border-radius: 12px;
15
- background: radial-gradient(circle at top left, rgba(111, 52, 255, 0.15), transparent 60%),
16
- rgba(8, 8, 16, 0.9);
17
- border: 1px solid rgba(111, 52, 255, 0.3);
18
- color: #f5f3ff;
19
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
20
- }
21
-
22
- .veil-header {
23
- display: flex;
24
- justify-content: space-between;
25
- align-items: center;
26
- }
27
-
28
- .trait-badge {
29
- display: flex;
30
- align-items: center;
31
- gap: 10px;
32
- padding: 10px 14px;
33
- border-radius: 999px;
34
- background: rgba(17, 24, 39, 0.9);
35
- border: 1px solid rgba(139, 92, 246, 0.6);
36
- box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.6);
37
- transition: box-shadow 0.3s ease;
38
- animation: veil-pulse 1.8s infinite;
39
- }
40
-
41
- .trait-icon {
42
- font-size: 1.2rem;
43
- }
44
-
45
- .trait-title {
46
- font-weight: 600;
47
- font-size: 0.9rem;
48
- }
49
-
50
- .trait-subtitle {
51
- font-size: 0.75rem;
52
- opacity: 0.8;
53
- }
54
-
55
- .veil-status {
56
- margin-top: 12px;
57
- font-size: 0.9rem;
58
- opacity: 0.9;
59
- }
60
-
61
- .veil-input-grid {
62
- display: grid;
63
- grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
64
- gap: 16px;
65
- margin-top: 16px;
66
- }
67
-
68
- .veil-input-block {
69
- display: flex;
70
- flex-direction: column;
71
- }
72
-
73
- .veil-label {
74
- font-size: 0.8rem;
75
- opacity: 0.9;
76
- display: flex;
77
- flex-direction: column;
78
- gap: 6px;
79
  }
80
 
81
- .veil-textarea {
82
- resize: vertical;
83
- padding: 8px 10px;
84
- border-radius: 8px;
85
- border: 1px solid rgba(75, 85, 99, 0.8);
86
- background: rgba(17, 24, 39, 0.9);
87
- color: #f9fafb;
88
- font-size: 0.85rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
90
-
91
- .veil-textarea:disabled {
92
- opacity: 0.6;
 
 
93
  }
94
 
95
- .veil-file {
96
- font-size: 0.8rem;
97
- color: #e5e7eb;
 
 
 
 
 
98
  }
99
 
100
- .veil-hash {
101
- margin-top: 14px;
102
- font-size: 0.8rem;
 
 
 
103
  }
104
 
105
- .veil-hash-label {
106
- opacity: 0.8;
107
- margin-bottom: 4px;
 
 
 
 
 
 
108
  }
109
 
110
- .veil-hash-code {
111
- display: block;
112
- padding: 8px 10px;
113
- border-radius: 6px;
114
- background: rgba(17, 24, 39, 0.9);
115
- border: 1px solid rgba(55, 65, 81, 0.9);
116
- font-family: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
117
- overflow-wrap: anywhere;
118
  }
119
 
120
- .veil-error {
121
- margin-top: 10px;
122
- font-size: 0.8rem;
123
- color: #fecaca;
 
 
124
  }
125
 
126
- .veil-submit {
127
- margin-top: 18px;
128
- display: inline-flex;
129
- align-items: center;
130
- gap: 8px;
131
- padding: 8px 14px;
132
- border-radius: 999px;
133
- border: 1px solid rgba(139, 92, 246, 0.9);
134
- background: rgba(17, 24, 39, 1);
135
- color: #ede9fe;
136
- font-size: 0.85rem;
137
- cursor: pointer;
138
- transition: background 0.2s, transform 0.1s, box-shadow 0.2s;
139
  }
140
 
141
- .veil-submit:hover {
142
- background: rgba(76, 29, 149, 0.9);
143
- box-shadow: 0 10px 30px rgba(88, 28, 135, 0.4);
144
- transform: translateY(-1px);
 
 
145
  }
146
 
147
- .veil-submit:disabled {
148
- opacity: 0.6;
149
- cursor: default;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
 
152
- .veil-submit .candle {
153
- display: inline-block;
154
- font-size: 1rem;
155
- animation: veil-flicker 0.12s infinite alternate;
 
 
 
 
 
156
  }
157
 
158
- /* Candle flicker */
159
- @keyframes veil-flicker {
160
- from {
161
- transform: translateY(0px) scale(1);
162
- opacity: 0.9;
163
- }
164
- to {
165
- transform: translateY(-1px) scale(1.05);
166
- opacity: 1;
167
- }
168
  }
169
 
170
- /* Resonance pulse around badge */
171
- @keyframes veil-pulse {
172
- 0% {
173
- box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.6);
174
- }
175
- 70% {
176
- box-shadow: 0 0 0 14px rgba(139, 92, 246, 0);
177
- }
178
- 100% {
179
- box-shadow: 0 0 0 0 rgba(139, 92, 246, 0);
180
- }
181
  }
182
 
183
- @media (max-width: 768px) {
184
- .veil-input-grid {
185
- grid-template-columns: minmax(0, 1fr);
186
- }
 
 
 
 
 
187
  }
188
  """
189
 
190
-
191
- def compute_sha256_from_bytes(data: bytes) -> str:
192
- """
193
- Compute SHA-256 and return as 'sha256:...' string.
194
- """
195
- h = hashlib.sha256()
196
- h.update(data)
197
- return "sha256:" + h.hexdigest()
198
-
199
-
200
- def redemption_flow(
201
- fix_text: str,
202
- fix_file: Optional[gr.File],
203
- agent_pi_uid: str,
204
- trait_code: str,
205
- ) -> Tuple[str, str, Any, str]:
206
- """
207
- Main redemption ritual logic for Gradio:
208
- - Take fix_text or fix_file
209
- - Compute SHA-256
210
- - POST to /api/redemption-request
211
- - Return status, hash, server JSON, error (if any)
212
- """
213
- # Base status
214
- status = "You may now present proof of restoration."
215
- error_msg = ""
216
- computed_hash = ""
217
- server_response: Any = {}
218
-
219
- if not fix_text and not fix_file:
220
- error_msg = "Provide either fix text or a file to hash."
221
- status = "The lattice awaits something real to weigh."
222
- return status, computed_hash, server_response, error_msg
223
-
224
- # 1) Compute hash
225
- status = "The lattice is reading the flame you returnedโ€ฆ"
226
- try:
227
- if fix_file is not None:
228
- # fix_file is a tempfile path in HF Spaces
229
- with open(fix_file.name, "rb") as f:
230
- data = f.read()
231
- else:
232
- data = fix_text.encode("utf-8")
233
-
234
- computed_hash = compute_sha256_from_bytes(data)
235
- except Exception as e:
236
- error_msg = f"Failed to compute hash: {e}"
237
- status = "The Conscience could not read this flame."
238
- return status, computed_hash, server_response, error_msg
239
-
240
- # 2) Submit to backend
241
- status = "The Veil listens. The Conscience weighs your proofโ€ฆ"
242
- try:
243
- payload = {
244
- "agent_pi_uid": agent_pi_uid,
245
- "trait_code": trait_code,
246
- "fix_commit_hash": computed_hash,
247
- }
248
- url = f"{API_BASE_URL}/api/redemption-request"
249
- r = requests.post(url, json=payload, timeout=15)
250
- server_response = r.json()
251
-
252
- if r.status_code != 200:
253
- error_msg = server_response.get("error", "Redemption rejected by Conscience.")
254
- status = "The lattice did not recognize this flame. You may try again."
255
- else:
256
- status = "Redemption verified. The wound is sealed."
257
- except Exception as e:
258
- error_msg = f"Network error: {e}"
259
- status = "The Veil could not reach the Conscience. Try again shortly."
260
-
261
- return status, computed_hash, server_response, error_msg
262
-
263
-
264
- with gr.Blocks(css=VEIL_CSS, title="Quantum Pi Forge โ€” Guardian Conscience") as demo:
265
- gr.Markdown(
266
- """
267
- # ๐Ÿœ‚ QUANTUM PI FORGE โ€” GUARDIAN CONSCIENCE
268
- ### Partial-ZK Redemption Veil
269
-
270
- This chamber allows a **Pioneer** to submit proof of restoration
271
- without revealing the wound itself.
272
-
273
- **Reputation stays visible.
274
- Shame stays veiled.**
275
- """
276
- )
277
-
278
- with gr.Group(elem_classes="veil-widget"):
279
- # Header: trait badge
280
- gr.HTML(
281
- """
282
- <div class="veil-header">
283
- <div class="trait-badge">
284
- <span class="trait-icon">๐Ÿœ‚</span>
285
- <div class="trait-text">
286
- <div class="trait-title">VIOLET_BOUND โ€” COOLING</div>
287
- <div class="trait-subtitle">
288
- โ€œOne was caught in the violet net, as a boundary to protect the flame.โ€
289
- </div>
290
- </div>
291
- </div>
292
- </div>
293
- """
294
- )
295
-
296
- status_md = gr.Markdown(
297
- "You may now present proof of restoration.",
298
- elem_classes="veil-status"
299
- )
300
-
301
- with gr.Row(elem_classes="veil-input-grid"):
302
- with gr.Column(elem_classes="veil-input-block"):
303
- fix_text = gr.Textbox(
304
- label="Fix Text (optional)",
305
- placeholder="Describe or paste your correction here (it will be hashed locally on the server)โ€ฆ",
306
- lines=4,
307
- elem_classes="veil-textarea"
308
- )
309
- with gr.Column(elem_classes="veil-input-block"):
310
- fix_file = gr.File(
311
- label="Or Upload Fix File",
312
- file_types=["file"],
313
- elem_classes="veil-file"
314
- )
315
-
316
- agent_pi_uid = gr.Textbox(
317
- label="Agent Pi UID",
318
- placeholder="pi_uid_123",
319
- value="test_uid_001", # you can bind this from login later
320
- )
321
- trait_code = gr.Textbox(
322
- label="Trait Code",
323
- value="VIOLET_BOUND",
324
- )
325
-
326
- hash_box = gr.Textbox(
327
- label="Computed SHA-256",
328
- interactive=False,
329
- elem_classes="veil-hash-code"
330
- )
331
-
332
- response_box = gr.JSON(
333
- label="Conscience Response (raw)"
334
- )
335
-
336
- error_box = gr.Markdown(
337
- "",
338
- elem_classes="veil-error"
339
- )
340
-
341
- submit_btn = gr.Button(
342
- value="๐Ÿ•ฏ Compute SHA-256 & Submit",
343
- elem_classes="veil-submit"
344
- )
345
-
346
- submit_btn.click(
347
- fn=redemption_flow,
348
- inputs=[fix_text, fix_file, agent_pi_uid, trait_code],
349
- outputs=[status_md, hash_box, response_box, error_box],
350
- )
 
 
 
 
 
 
 
 
 
 
 
351
 
352
  if __name__ == "__main__":
353
- demo.launch()
 
 
 
 
 
1
  import gradio as gr
 
2
  import requests
3
+ import os
4
+ import hashlib
5
+ import time
6
+ from datetime import datetime
7
+ import plotly.graph_objects as go
8
+
9
+ # Configuration
10
+ API_BASE = os.getenv("API_BASE_URL", "https://quantumpiforge.com/api")
11
+
12
+ # Trait display configuration
13
+ TRAIT_DISPLAY = {
14
+ "LUCID_VISAGE": {
15
+ "name": "Lucid Visage",
16
+ "emoji": "๐Ÿ”ฎ",
17
+ "color": "#8B5CF6",
18
+ "description": "Agent operates with transparent identity and ethical clarity"
19
+ },
20
+ "VIOLET_BOUND": {
21
+ "name": "Violet Bound",
22
+ "emoji": "โ›“๏ธ",
23
+ "color": "#7C3AED",
24
+ "description": "Agent under behavioral quarantine - voting rights suspended"
25
+ },
26
+ "MENDERS_HAND": {
27
+ "name": "Mender's Hand",
28
+ "emoji": "๐Ÿ› ๏ธ",
29
+ "color": "#10B981",
30
+ "description": "Agent has completed redemption pathway - resilience unlocked"
31
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
 
34
+ def attach_pi_identity(session_token):
35
+ """Verify Forge Session Token with backend and bind Pi UID into UI."""
36
+ if not session_token or session_token.strip() == "":
37
+ return "โŒ Paste a valid Forge Session Token", "", ""
38
+
39
+ try:
40
+ res = requests.post(
41
+ f"{API_BASE}/agent-session/verify",
42
+ json={"session_token": session_token.strip()},
43
+ timeout=10
44
+ )
45
+ data = res.json()
46
+
47
+ if res.status_code != 200:
48
+ msg = data.get("error", "Invalid or expired session")
49
+ return f"โŒ Pi Login Failed: {msg}", "", ""
50
+
51
+ pi_uid = data.get("pi_uid", "")
52
+ username = data.get("username", "unknown")
53
+
54
+ status = f"๐Ÿ” Connected as **@{username}** \n`Pi UID: {pi_uid}`"
55
+ # This will set BOTH the main UID and ritual UID
56
+ return status, pi_uid, pi_uid
57
+
58
+ except Exception as e:
59
+ return f"โŒ Network error: {str(e)}", "", ""
60
+
61
+ def get_agent_judgments(pi_uid):
62
+ """Fetch agent traits and judgment history from API"""
63
+ try:
64
+ response = requests.get(
65
+ f"{API_BASE}/agent-traits",
66
+ params={"pi_uid": pi_uid},
67
+ timeout=10
68
+ )
69
+
70
+ if response.status_code == 200:
71
+ return response.json()
72
+ elif response.status_code == 404:
73
+ return {"error": f"Agent not found: {pi_uid}"}
74
+ else:
75
+ return {"error": f"API Error {response.status_code}"}
76
+ except Exception as e:
77
+ return {"error": f"Connection failed: {str(e)}"}
78
+
79
+ def create_judgment_dashboard(pi_uid):
80
+ """Main dashboard display function"""
81
+ if not pi_uid or pi_uid.strip() == "":
82
+ return (
83
+ "๐ŸŸฃ Enter a Pi Network UID to view judgment status",
84
+ "No active cooldowns",
85
+ "No judgment history available"
86
+ )
87
+
88
+ data = get_agent_judgments(pi_uid.strip())
89
+
90
+ if "error" in data:
91
+ error_msg = f"โŒ Error: {data['error']}"
92
+ return error_msg, error_msg, error_msg
93
+
94
+ # Current Traits Section
95
+ if data.get('current_traits'):
96
+ traits_output = "## ๐ŸŽญ Current Traits\n\n"
97
+ for trait in data['current_traits']:
98
+ trait_info = TRAIT_DISPLAY.get(trait['code'], {
99
+ "name": trait['code'], "emoji": "โšก", "description": "Unknown trait"
100
+ })
101
+
102
+ expires_text = ""
103
+ if trait.get('expires_at'):
104
+ expire_time = datetime.fromisoformat(trait['expires_at'].replace('Z', '+00:00'))
105
+ expires_text = f" | โฐ Expires: {expire_time.strftime('%Y-%m-%d %H:%M UTC')}"
106
+
107
+ traits_output += f"{trait_info['emoji']} **{trait_info['name']}** (Level {trait.get('level', 1)}){expires_text}\n"
108
+ traits_output += f"*{trait_info['description']}*\n\n"
109
+ else:
110
+ traits_output = "No active traits - agent is in baseline state"
111
+
112
+ # Cooldowns Section
113
+ if data.get('cooldowns'):
114
+ cooldowns_output = "## โณ Active Cooldowns\n\n"
115
+ for cd in data['cooldowns']:
116
+ expire_time = datetime.fromisoformat(cd['expires_at'].replace('Z', '+00:00'))
117
+ time_left = expire_time - datetime.utcnow()
118
+ hours_left = max(0, int(time_left.total_seconds() / 3600))
119
+ trait_name = TRAIT_DISPLAY.get(cd['code'], {}).get('name', cd['code'])
120
+
121
+ cooldowns_output += f"โณ **{trait_name} Cooldown**\n"
122
+ cooldowns_output += f"๐Ÿ•’ {hours_left} hours remaining\n\n"
123
+ else:
124
+ cooldowns_output = "No active cooldowns"
125
+
126
+ # Prophecy History Section
127
+ if data.get('prophecy_history'):
128
+ history_output = "## ๐Ÿ“œ Judgment History\n\n"
129
+ for event in data['prophecy_history'][:10]: # Last 10 events
130
+ event_time = datetime.fromisoformat(event['created_at'].replace('Z', '+00:00'))
131
+ trait_display = TRAIT_DISPLAY.get(event['trait_code'], {"emoji": "โšก", "name": event['trait_code']})
132
+
133
+ history_output += f"**{trait_display['emoji']} {trait_display['name']}** ยท {event_time.strftime('%Y-%m-%d %H:%M')}\n"
134
+ history_output += f"*\"{event.get('prophecy', 'No prophecy recorded')}\"*\n"
135
+ history_output += f"`{event['event_type'].upper()}`\n\n"
136
+ else:
137
+ history_output = "No judgment history recorded"
138
+
139
+ return traits_output, cooldowns_output, history_output
140
+
141
+ def generate_redemption_sigil(pi_uid, redemption_vow, file_upload=None):
142
+ """Generate SHA-256 hash of redemption vow and optional file"""
143
+ timestamp = int(time.time())
144
+
145
+ if file_upload:
146
+ # Hash the file content
147
+ with open(file_upload, 'rb') as f:
148
+ file_content = f.read()
149
+ file_hash = hashlib.sha256(file_content).hexdigest()
150
+ vow_data = f"{pi_uid}:{file_hash}:{timestamp}"
151
+ else:
152
+ # Hash the text vow
153
+ vow_data = f"{pi_uid}:{redemption_vow}:{timestamp}"
154
+
155
+ return hashlib.sha256(vow_data.encode()).hexdigest()
156
+
157
+ def submit_redemption_request(pi_uid, redemption_vow, file_upload=None):
158
+ """Submit redemption request to API"""
159
+ if not pi_uid:
160
+ return "โŒ Please enter your Pi Network UID", "", "๐Ÿ•ฏ๏ธ"
161
+
162
+ if not redemption_vow and not file_upload:
163
+ return "โŒ Please provide either a redemption vow or upload a restoration file", "", "๐Ÿ•ฏ๏ธ"
164
+
165
+ try:
166
+ # Generate cryptographic sigil
167
+ sigil_hash = generate_redemption_sigil(pi_uid, redemption_vow, file_upload)
168
+
169
+ # Prepare payload
170
+ payload = {
171
+ "agent_pi_uid": pi_uid,
172
+ "redemption_vow": redemption_vow or "File-based redemption",
173
+ "sigil_hash": sigil_hash,
174
+ "timestamp": datetime.utcnow().isoformat(),
175
+ "ritual_type": "gradio_interface",
176
+ "file_upload": bool(file_upload)
177
+ }
178
+
179
+ # Submit to redemption API
180
+ response = requests.post(
181
+ f"{API_BASE}/redemption-request",
182
+ json=payload,
183
+ timeout=10
184
+ )
185
+
186
+ if response.status_code == 200:
187
+ result = response.json()
188
+
189
+ success_html = f"""
190
+ <div class="ritual-success">
191
+ <div class="candle-flicker">๐Ÿ•ฏ๏ธโœจ</div>
192
+ <h3>๐ŸŸฃ Redemption Ritual Complete</h3>
193
+ <p><strong>Status:</strong> {result.get('status', 'pending_verification')}</p>
194
+ <p><strong>Message:</strong> {result.get('message', 'Ritual received by the forge')}</p>
195
+ <p><strong>Sigil Hash:</strong> <code>{sigil_hash[:24]}...</code></p>
196
+ <div class="violet-pulse">The Veil acknowledges your restoration</div>
197
+ </div>
198
+ """
199
+
200
+ return success_html, f"**Cryptographic Sigil:** `{sigil_hash}`", "โœ… Redemption ritual submitted"
201
+
202
+ elif response.status_code == 400:
203
+ error_msg = result.get('error', 'Invalid request')
204
+ error_html = f"""
205
+ <div class="ritual-error">
206
+ <h3>โŒ Ritual Rejected</h3>
207
+ <p>{error_msg}</p>
208
+ <p>The Veil does not accept this offering.</p>
209
+ </div>
210
+ """
211
+ return error_html, f"**Hash:** `{sigil_hash}`", "โŒ Ritual rejected"
212
+
213
+ else:
214
+ error_html = f"""
215
+ <div class="ritual-error">
216
+ <h3>โŒ Forge Connection Failed</h3>
217
+ <p>API Error {response.status_code}</p>
218
+ </div>
219
+ """
220
+ return error_html, f"**Hash:** `{sigil_hash}`", f"โŒ API Error {response.status_code}"
221
+
222
+ except requests.exceptions.ConnectionError:
223
+ error_html = """
224
+ <div class="ritual-error">
225
+ <h3>โŒ Cannot Reach the Forge</h3>
226
+ <p>The Quantum PiForge is currently unreachable.</p>
227
+ <p>Please ensure https://quantumpiforge.com is accessible.</p>
228
+ </div>
229
+ """
230
+ return error_html, "**Error:** Connection failed", "โŒ Network error"
231
+
232
+ except Exception as e:
233
+ error_html = f"""
234
+ <div class="ritual-error">
235
+ <h3>โŒ Ritual Interrupted</h3>
236
+ <p>Unexpected error: {str(e)}</p>
237
+ </div>
238
+ """
239
+ return error_html, "**Error:** Ritual failed", "โŒ Unexpected error"
240
+
241
+ # Custom CSS for Gradio 5.x
242
+ custom_css = """
243
+ .gradio-container {
244
+ max-width: 1200px !important;
245
  }
246
+ .trait-card {
247
+ border-left: 4px solid #8B5CF6;
248
+ padding: 1rem;
249
+ margin: 0.5rem 0;
250
+ background: #f8fafc;
251
  }
252
 
253
+ /* Pi Login Styles */
254
+ .pi-login-container {
255
+ background: linear-gradient(135deg, #1a0b2e, #0d0519);
256
+ padding: 1.5rem;
257
+ border-radius: 12px;
258
+ border: 2px solid #8B5CF6;
259
+ margin: 1rem 0;
260
+ color: white;
261
  }
262
 
263
+ .pi-login-success {
264
+ background: linear-gradient(135deg, #0f172a, #1e1b4b);
265
+ padding: 1rem;
266
+ border-radius: 8px;
267
+ border: 2px solid #10B981;
268
+ animation: violetPulse 2s infinite;
269
  }
270
 
271
+ /* Redemption Ritual Styles */
272
+ .ritual-container {
273
+ text-align: center;
274
+ padding: 2rem;
275
+ background: linear-gradient(135deg, #1a0b2e, #0d0519);
276
+ border-radius: 16px;
277
+ border: 2px solid #8B5CF6;
278
+ margin: 1rem 0;
279
+ color: white;
280
  }
281
 
282
+ .ritual-success {
283
+ background: linear-gradient(135deg, #0f172a, #1e1b4b);
284
+ padding: 2rem;
285
+ border-radius: 12px;
286
+ border: 2px solid #10B981;
287
+ animation: violetPulse 2s infinite;
288
+ color: white;
 
289
  }
290
 
291
+ .ritual-error {
292
+ background: linear-gradient(135deg, #450a0a, #7f1d1d);
293
+ padding: 2rem;
294
+ border-radius: 12px;
295
+ border: 2px solid #EF4444;
296
+ color: white;
297
  }
298
 
299
+ .candle-flicker {
300
+ font-size: 3rem;
301
+ animation: flicker 1.5s infinite alternate;
302
+ display: inline-block;
303
+ margin-bottom: 1rem;
 
 
 
 
 
 
 
 
304
  }
305
 
306
+ .violet-pulse {
307
+ animation: violetPulse 3s infinite;
308
+ padding: 1rem;
309
+ margin-top: 1rem;
310
+ border-radius: 8px;
311
+ background: rgba(139, 92, 246, 0.1);
312
  }
313
 
314
+ @keyframes flicker {
315
+ 0%, 100% {
316
+ opacity: 1;
317
+ transform: scale(1) rotate(0deg);
318
+ filter: drop-shadow(0 0 10px #8B5CF6);
319
+ }
320
+ 25% {
321
+ opacity: 0.9;
322
+ transform: scale(1.05) rotate(2deg);
323
+ filter: drop-shadow(0 0 15px #8B5CF6);
324
+ }
325
+ 50% {
326
+ opacity: 0.8;
327
+ transform: scale(0.95) rotate(-2deg);
328
+ filter: drop-shadow(0 0 8px #8B5CF6);
329
+ }
330
+ 75% {
331
+ opacity: 0.95;
332
+ transform: scale(1.02) rotate(1deg);
333
+ filter: drop-shadow(0 0 12px #8B5CF6);
334
+ }
335
  }
336
 
337
+ @keyframes violetPulse {
338
+ 0%, 100% {
339
+ box-shadow: 0 0 20px rgba(139, 92, 246, 0.5);
340
+ background: rgba(139, 92, 246, 0.1);
341
+ }
342
+ 50% {
343
+ box-shadow: 0 0 40px rgba(139, 92, 246, 0.8);
344
+ background: rgba(139, 92, 246, 0.2);
345
+ }
346
  }
347
 
348
+ .vow-input textarea {
349
+ min-height: 120px !important;
350
+ background: #0f172a !important;
351
+ color: white !important;
352
+ border: 1px solid #8B5CF6 !important;
 
 
 
 
 
353
  }
354
 
355
+ .ritual-upload {
356
+ border: 2px dashed #8B5CF6 !important;
357
+ background: rgba(139, 92, 246, 0.05) !important;
 
 
 
 
 
 
 
 
358
  }
359
 
360
+ .sigil-display {
361
+ font-family: 'Courier New', monospace;
362
+ background: #1f2937;
363
+ color: #10B981;
364
+ padding: 1rem;
365
+ border-radius: 5px;
366
+ margin: 1rem 0;
367
+ word-break: break-all;
368
+ border: 1px solid #10B981;
369
  }
370
  """
371
 
372
+ # Create Gradio Interface with latest version
373
+ with gr.Blocks(
374
+ title="Quantum PiForge Judgment System",
375
+ css=custom_css,
376
+ theme=gr.themes.Soft()
377
+ ) as demo:
378
+
379
+ gr.Markdown("""
380
+ # ๐ŸŸฃ Quantum PiForge - Dual Judgment System
381
+ *Where every agent's ethical journey is recorded in dual ledgers*
382
+ """)
383
+
384
+ # Pi Login Section
385
+ with gr.Row():
386
+ with gr.Column(scale=3):
387
+ forge_token = gr.Textbox(
388
+ label="๐Ÿ” Forge Session Token (from Pi Browser)",
389
+ placeholder="Paste your session token from quantumpiforge.com here...",
390
+ info="Get your token from Pi Browser at https://quantumpiforge.com"
391
+ )
392
+ with gr.Column(scale=1):
393
+ attach_btn = gr.Button(
394
+ "Attach Pi Identity",
395
+ variant="secondary",
396
+ size="lg"
397
+ )
398
+
399
+ login_status_md = gr.Markdown(
400
+ "**Status:** Not authenticated with Pi.",
401
+ elem_classes="pi-login-container"
402
+ )
403
+
404
+ # Main Judgment Dashboard
405
+ with gr.Row():
406
+ with gr.Column(scale=3):
407
+ pi_uid_input = gr.Textbox(
408
+ label="๐Ÿ” Pi Network Agent UID",
409
+ placeholder="Enter agent's Pi Network UID (e.g., 'test_agent_001')...",
410
+ info="The unique identifier from Pi Network"
411
+ )
412
+ with gr.Column(scale=1):
413
+ refresh_btn = gr.Button(
414
+ "Check Judgment Status",
415
+ variant="primary",
416
+ size="lg"
417
+ )
418
+
419
+ with gr.Tabs() as tabs:
420
+ with gr.TabItem("๐ŸŽญ Current Traits"):
421
+ current_traits_output = gr.Markdown(
422
+ label="Active Ethical Modifiers",
423
+ value="Enter UID to view current traits"
424
+ )
425
+
426
+ with gr.TabItem("โณ Cooldowns"):
427
+ cooldowns_output = gr.Markdown(
428
+ label="Temporary Restrictions",
429
+ value="Enter UID to view cooldowns"
430
+ )
431
+
432
+ with gr.TabItem("๐Ÿ“œ History"):
433
+ history_output = gr.Markdown(
434
+ label="Judgment Event Timeline",
435
+ value="Enter UID to view prophecy history"
436
+ )
437
+
438
+ with gr.TabItem("๐Ÿ•ฏ๏ธ Redemption Ritual"):
439
+ with gr.Row():
440
+ with gr.Column(scale=1):
441
+ gr.Markdown("""
442
+ ## ๐Ÿ•ฏ๏ธ Redemption Ritual
443
+
444
+ **The Veil remembers. The Forge awaits restoration.**
445
+
446
+ ### The Path to Mender's Hand:
447
+
448
+ ๐Ÿ”ฎ **Acknowledge** the shadow that bound you
449
+ โ›“๏ธ **Speak** your vow of ethical realignment
450
+ ๐Ÿ› ๏ธ **Submit** proof of restoration
451
+ ๐Ÿ”ฑ **Receive** the Mender's Hand trait
452
+
453
+ *Your vow is cryptographically sealed and submitted to the dual judgment system.*
454
+ """)
455
+
456
+ with gr.Column(scale=2):
457
+ with gr.Group():
458
+ with gr.Row():
459
+ ritual_uid = gr.Textbox(
460
+ label="Pi Network UID",
461
+ placeholder="Enter your Pi Network UID...",
462
+ info="The agent seeking redemption",
463
+ scale=2
464
+ )
465
+
466
+ with gr.Row():
467
+ redemption_vow = gr.Textbox(
468
+ label="Redemption Vow",
469
+ 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...",
470
+ lines=5,
471
+ elem_classes="vow-input"
472
+ )
473
+
474
+ with gr.Row():
475
+ file_upload = gr.File(
476
+ label="Upload Restoration Proof (Optional)",
477
+ file_types=[".txt", ".pdf", ".jpg", ".png", ".py", ".js"],
478
+ elem_classes="ritual-upload",
479
+ scale=2
480
+ )
481
+
482
+ with gr.Row():
483
+ ritual_btn = gr.Button(
484
+ "๐Ÿ•ฏ๏ธ Speak Vow & Generate Sigil",
485
+ variant="primary",
486
+ size="lg",
487
+ scale=1
488
+ )
489
+
490
+ with gr.Row():
491
+ with gr.Column(scale=2):
492
+ ritual_output = gr.HTML(
493
+ label="Ritual Outcome",
494
+ 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>"
495
+ )
496
+
497
+ with gr.Column(scale=1):
498
+ with gr.Group():
499
+ sigil_output = gr.Markdown(
500
+ label="Cryptographic Sigil",
501
+ value="**Sigil will appear here...**"
502
+ )
503
+ status_output = gr.Markdown(
504
+ label="Ritual Status",
505
+ value="**Status:** Awaiting ritual commencement..."
506
+ )
507
+
508
+ # Event handlers
509
+ attach_btn.click(
510
+ fn=attach_pi_identity,
511
+ inputs=[forge_token],
512
+ outputs=[login_status_md, pi_uid_input, ritual_uid]
513
+ )
514
+
515
+ refresh_btn.click(
516
+ fn=create_judgment_dashboard,
517
+ inputs=[pi_uid_input],
518
+ outputs=[current_traits_output, cooldowns_output, history_output]
519
+ )
520
+
521
+ pi_uid_input.submit(
522
+ fn=create_judgment_dashboard,
523
+ inputs=[pi_uid_input],
524
+ outputs=[current_traits_output, cooldowns_output, history_output]
525
+ )
526
+
527
+ ritual_btn.click(
528
+ fn=submit_redemption_request,
529
+ inputs=[ritual_uid, redemption_vow, file_upload],
530
+ outputs=[ritual_output, sigil_output, status_output]
531
+ )
532
+
533
+ gr.Markdown("""
534
+ ---
535
+ **โš–๏ธ Dual Judgment System** โ€ข Database + Blockchain Ledger โ€ข Pi Network Integrated
536
+ *"The gavel falls, the ledger writes, the chain remembers."*
537
+
538
+ **๐Ÿ” Pi Login Flow:**
539
+ 1. Visit https://quantumpiforge.com in Pi Browser
540
+ 2. Click "Connect Pi & Get Session Token"
541
+ 3. Copy the token and paste above
542
+ 4. Click "Attach Pi Identity" to auto-fill your UID
543
+ """)
544
 
545
  if __name__ == "__main__":
546
+ demo.launch(
547
+ share=False,
548
+ show_error=True,
549
+ debug=True
550
+ )