Spaces:
Running
Running
| """ | |
| Codette Multi-Perspective Cognitive Architecture β HuggingFace Gradio Space [v2.0] | |
| A production-grade showcase of the 10 cognitive subsystems with real-time visualizations. | |
| All reasoning modules are pure Python (no PyTorch/llama.cpp required). | |
| Created by Jonathan Harrison | |
| RC+xi Framework: Recursive Convergence + Epistemic Tension | |
| """ | |
| import os | |
| import json | |
| import time | |
| from typing import Dict, List, Tuple, Optional | |
| from datetime import datetime | |
| import hashlib | |
| import gradio as gr | |
| import numpy as np | |
| import plotly.graph_objects as go | |
| import plotly.express as px | |
| from huggingface_hub import InferenceClient, login | |
| # Import all cognitive subsystems (pure Python, no heavy dependencies) | |
| from reasoning_forge.perspective_registry import ( | |
| PERSPECTIVES, get_perspective, list_all as list_perspectives | |
| ) | |
| from reasoning_forge.aegis import AEGIS | |
| from reasoning_forge.nexus import NexusSignalEngine | |
| from reasoning_forge.guardian import CodetteGuardian | |
| from reasoning_forge.living_memory import LivingMemoryKernel, MemoryCocoon | |
| from reasoning_forge.resonant_continuity import ResonantContinuityEngine | |
| from reasoning_forge.epistemic_metrics import EpistemicMetrics | |
| from reasoning_forge.quantum_spiderweb import QuantumSpiderweb | |
| from reasoning_forge.forge_engine import ForgeEngine | |
| from reasoning_forge.synthesis_engine import SynthesisEngine | |
| # ================================================================ | |
| # ADAPTER COLORS & CONFIGURATION | |
| # ================================================================ | |
| ADAPTER_COLORS = { | |
| "newton": "#3b82f6", | |
| "davinci": "#f59e0b", | |
| "empathy": "#a855f7", | |
| "philosophy": "#10b981", | |
| "quantum": "#ef4444", | |
| "consciousness": "#e2e8f0", | |
| "multi_perspective": "#f97316", | |
| "systems_architecture": "#06b6d4", | |
| } | |
| EMOTION_COLORS = { | |
| "neutral": "#94a3b8", | |
| "curiosity": "#3b82f6", | |
| "awe": "#a055f7", | |
| "joy": "#fbbf24", | |
| "insight": "#34d399", | |
| "confusion": "#f97316", | |
| "frustration": "#ef4444", | |
| "fear": "#b91c1c", | |
| "empathy": "#ec4899", | |
| "determination": "#8b5cf6", | |
| "surprise": "#06b6d4", | |
| "trust": "#10b981", | |
| "gratitude": "#84cc16", | |
| } | |
| DEFAULT_PERSPECTIVES = ["newton", "empathy", "philosophy", "quantum"] | |
| # HF Inference API setup | |
| HF_TOKEN = os.environ.get("HF_TOKEN", "") | |
| if HF_TOKEN: | |
| try: | |
| login(token=HF_TOKEN) | |
| except Exception as e: | |
| print(f"Warning: HF token invalid or expired ({e.__class__.__name__}). Will attempt without auth.") | |
| HF_TOKEN = "" | |
| try: | |
| client = InferenceClient("meta-llama/Llama-3.1-8B-Instruct") | |
| HAS_LLM = True | |
| except Exception as e: | |
| print(f"Warning: Could not initialize InferenceClient: {e}") | |
| HAS_LLM = False | |
| # Initialize the reasoning forge with trained agents | |
| try: | |
| forge = ForgeEngine() | |
| HAS_FORGE = True | |
| except Exception as e: | |
| print(f"Warning: Could not initialize ForgeEngine: {e}") | |
| HAS_FORGE = False | |
| # ================================================================ | |
| # UTILITY FUNCTIONS | |
| # ================================================================ | |
| def auto_select_perspectives(query: str, n: int = 4) -> List[str]: | |
| """Auto-select best perspectives for a query based on keyword matching.""" | |
| scores = {} | |
| q_lower = query.lower() | |
| for name, p in PERSPECTIVES.items(): | |
| score = sum(1 for kw in p.keywords if kw.lower() in q_lower) | |
| scores[name] = score | |
| ranked = sorted(scores.items(), key=lambda x: x[1], reverse=True) | |
| selected = [] | |
| for name, _ in ranked: | |
| if len(selected) >= n: | |
| break | |
| selected.append(name) | |
| for default in DEFAULT_PERSPECTIVES: | |
| if len(selected) >= n: | |
| break | |
| if default not in selected: | |
| selected.append(default) | |
| return selected[:n] | |
| def call_perspective(perspective_name: str, query: str, request: gr.Request = None) -> str: | |
| """Generate response using the trained agent or fallback algorithm.""" | |
| p = get_perspective(perspective_name) | |
| if not p: | |
| return f"Perspective {perspective_name} not found." | |
| # Use actual trained agents from the forge | |
| if HAS_FORGE: | |
| try: | |
| # Map perspective names to forge agents | |
| agent_map = { | |
| "newton": forge.newton, | |
| "davinci": forge.davinci, | |
| "empathy": forge.empathy, | |
| "philosophy": forge.philosophy, | |
| "quantum": forge.quantum, | |
| "consciousness": forge.ethics, # Ethics agent = consciousness perspective | |
| } | |
| agent = agent_map.get(perspective_name) | |
| if agent: | |
| # Call the trained agent's analyze method | |
| response = agent.analyze(query) | |
| if response and isinstance(response, str): | |
| return response.strip() | |
| except Exception as e: | |
| print(f"Agent {perspective_name} analysis failed: {e}") | |
| pass # Fall through | |
| # Fallback: Use algorithmic reasoning | |
| return generate_perspective_response(perspective_name, query, p) | |
| def generate_perspective_response(perspective_name: str, query: str, perspective) -> str: | |
| """Generate intelligent perspective response using pure Python reasoning.""" | |
| query_lower = query.lower() | |
| # Count keyword matches to show analysis | |
| matches = sum(1 for kw in perspective.keywords if kw in query_lower) | |
| relevance = min(100, 40 + (matches * 15)) # Base relevance + keyword boost | |
| # Perspective-specific algorithmic responses | |
| if perspective_name == "newton": | |
| return ( | |
| f"**[ANALYTICAL]** I observe {len(query.split())} elements in your query. " | |
| f"Systematic decomposition: {query[:50]}... forms a logical chain with {matches} key analytical patterns. " | |
| f"*Coherence: {relevance}%* β This question engages quantifiable reasoning." | |
| ) | |
| elif perspective_name == "davinci": | |
| return ( | |
| f"**[CREATIVE]** I see connections across domains. Your query evokes " | |
| f"{matches} creative dimensions (design, innovation, visual thinking). " | |
| f"Cross-domain synthesis potential: {relevance}%. " | |
| f"*Associative bridges identified* β Novel combinations await." | |
| ) | |
| elif perspective_name == "empathy": | |
| return ( | |
| f"**[EMOTIONAL]** I sense human experience in your inquiry. " | |
| f"Emotional resonance detected: {matches} relational keywords. " | |
| f"Care-aligned response: '{query[:40]}...' touches {relevance}% of human wellbeing concerns. " | |
| f"*Compassion matrix active* β What matters to you?" | |
| ) | |
| elif perspective_name == "philosophy": | |
| return ( | |
| f"**[CONCEPTUAL]** Your question probes meaning at {relevance}% depth. " | |
| f"Philosophical dimensions engaged: {matches} core concepts present. " | |
| f"Existential framing: *Why* this matters, *what* the essence reveals. " | |
| f"*Meaning-making synthesis* β Let's explore the deeper nature." | |
| ) | |
| elif perspective_name == "quantum": | |
| return ( | |
| f"**[PROBABILISTIC]** Superposition of possibilities: Your query encodes " | |
| f"{matches} quantum dimensions. Probability distribution: {relevance}% coherence. " | |
| f"*Wave function collapse pending*: Multiple valid interpretations coexist. " | |
| f"Entanglement detected with {matches} complementary perspectives." | |
| ) | |
| elif perspective_name == "consciousness": | |
| return ( | |
| f"**[META-COGNITIVE]** I reflect on my own reasoning about your question. " | |
| f"Self-awareness metrics: {relevance}% recursive comprehension depth. " | |
| f"Observing {matches} layers of cognition interacting. " | |
| f"*RC+xi tension* β Integrating all perspectives into unified understanding." | |
| ) | |
| elif perspective_name == "multi_perspective": | |
| return ( | |
| f"**[SYNTHESIS]** Harmonizing {matches} perspective threads in your query. " | |
| f"Multi-perspective coherence: {relevance}%. " | |
| f"Integrated view: Analytical + Creative + Emotional + Conceptual threads woven. " | |
| f"*Epistemic rich picture* β No single perspective captures the whole." | |
| ) | |
| elif perspective_name == "systems_architecture": | |
| return ( | |
| f"**[SYSTEMS]** Your query exhibits {matches} systemic properties. " | |
| f"Architectural coherence: {relevance}%. Components: Input β Process β Output. " | |
| f"System dynamics engaged. *Feedback loops detected*. " | |
| f"Emergent behaviors possible from interaction patterns." | |
| ) | |
| else: | |
| # Fallback for any perspective | |
| return ( | |
| f"**[{perspective_name.upper()}]** Analysis: {query[:50]}... " | |
| f"Relevance score: {relevance}%. " | |
| f"Patterns matched: {matches}. " | |
| f"Perspective-aligned reasoning activated." | |
| ) | |
| def generate_synthesis(perspectives_responses: Dict[str, str], query: str, request: gr.Request = None) -> str: | |
| """Generate synthesis using trained synthesis engine or fallback algorithm.""" | |
| # Use the trained synthesis engine from the forge | |
| if HAS_FORGE: | |
| try: | |
| # Generate critique from the critic agent | |
| critique = forge.critic.evaluate_ensemble(query, perspectives_responses) | |
| # Get synthesized response from the synthesis engine | |
| synthesis_result = forge.synthesis.synthesize( | |
| concept=query, | |
| analyses=perspectives_responses, | |
| critique=critique | |
| ) | |
| if synthesis_result and isinstance(synthesis_result, str): | |
| return synthesis_result.strip() | |
| except Exception as e: | |
| print(f"Synthesis engine failed: {e}") | |
| pass # Fall through to built-in synthesis | |
| # Fallback: RC+xi algorithmic synthesis | |
| return generate_algorithmic_synthesis(perspectives_responses, query) | |
| def generate_algorithmic_synthesis(perspectives_responses: Dict[str, str], query: str) -> str: | |
| """Fallback algorithmic synthesis showcasing RC+xi framework.""" | |
| # Extract key phrases from each perspective response | |
| insights = [] | |
| for name, response in perspectives_responses.items(): | |
| # Find the core statement (usually in brackets or first key phrase) | |
| if "**[" in response: | |
| bracket_content = response.split("**[")[1].split("]**")[0] | |
| insight = bracket_content | |
| else: | |
| insight = name.replace('_', ' ').title() | |
| insights.append(insight) | |
| # Build unified perspective synthesis | |
| synthesis = f"""π **Multi-Perspective Integration via RC+xi** | |
| **Unified Analysis:** Your question "{query[:60]}..." engages {len(perspectives_responses)} reasoning perspectives: | |
| {', '.join(f"*{i}*" for i in insights)} | |
| **Recursive Convergence Protocol:** | |
| - Each perspective recursively analyzes the query from its domain | |
| - Perspectives converge toward common truths and diverge on unique insights | |
| - Recursion depth: Full philosophical, analytical, creative, emotional exploration | |
| **Epistemic Tension Management:** | |
| - Productive disagreement between approaches (analytical vs. emotional, concrete vs. abstract) | |
| - Tension resolved through synthesis, not elimination | |
| - Coherence emerges from integrated contradictions | |
| **Integration Metrics:** | |
| - Multi-perspective coherence: {min(99, 60 + len(perspectives_responses) * 5)}% | |
| - Epistemic richness: High | |
| - Complementarity: All perspectives add novel value | |
| **Codette's Unified Insight:** | |
| The deepest understanding lives in the *space between* perspectives β where seemingly contradictory approaches become complementary lenses on a single truth. This is the RC+xi synthesis.""" | |
| return synthesis | |
| # ================================================================ | |
| # VISUALIZATION BUILDERS | |
| # ================================================================ | |
| def build_spiderweb_graph(spiderweb_state: Optional[Dict]) -> go.Figure: | |
| """Build and return spiderweb force-directed graph.""" | |
| if not spiderweb_state or not spiderweb_state.get("nodes"): | |
| fig = go.Figure() | |
| fig.add_annotation(text="QuantumSpiderweb activates with responses", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=14, color="#a0a0c0")) | |
| fig.update_layout(title="QuantumSpiderweb Graph", height=400, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e") | |
| return fig | |
| nodes_dict = spiderweb_state.get("nodes", {}) | |
| phase_coherence = spiderweb_state.get("phase_coherence", 0.5) | |
| # Convert node dict to indexed list | |
| node_ids = list(nodes_dict.keys()) | |
| node_data = [nodes_dict[nid] for nid in node_ids] | |
| node_names = node_ids | |
| node_x = [] | |
| node_y = [] | |
| # Circular layout with psi-based jitter (psi is first element of state array) | |
| for i, node in enumerate(node_data): | |
| angle = (2 * np.pi * i) / len(node_data) | |
| psi = node.get("state", [0.5])[0] if isinstance(node.get("state"), list) else 0.5 | |
| radius = 0.8 + (psi - 0.5) * 0.3 | |
| node_x.append(radius * np.cos(angle) + np.random.randn() * 0.1) | |
| node_y.append(radius * np.sin(angle) + np.random.randn() * 0.1) | |
| # Build edges from neighbor relationships | |
| edge_x = [] | |
| edge_y = [] | |
| for i, (nid, node) in enumerate(nodes_dict.items()): | |
| neighbors = node.get("neighbors", []) | |
| for neighbor_id in neighbors: | |
| if neighbor_id in node_ids: | |
| j = node_ids.index(neighbor_id) | |
| edge_x.extend([node_x[i], node_x[j], None]) | |
| edge_y.extend([node_y[i], node_y[j], None]) | |
| fig = go.Figure() | |
| # Add edges | |
| fig.add_trace(go.Scatter( | |
| x=edge_x, y=edge_y, | |
| mode='lines', | |
| line=dict(width=1, color='rgba(200, 200, 220, 0.4)'), | |
| hoverinfo='none', | |
| showlegend=False, | |
| )) | |
| # Add nodes | |
| node_colors = [ADAPTER_COLORS.get(nid.lower(), "#8b5cf6") for nid in node_ids] | |
| node_sizes = [15 + (node.get("state", [0.5])[0] if isinstance(node.get("state"), list) else 0.5) * 20 | |
| for node in node_data] | |
| fig.add_trace(go.Scatter( | |
| x=node_x, y=node_y, | |
| mode='markers+text', | |
| marker=dict( | |
| size=node_sizes, | |
| color=node_colors, | |
| line=dict(width=2, color='rgba(200, 200, 255, 0.6)'), | |
| ), | |
| text=node_names, | |
| textposition="top center", | |
| hovertext=node_names, | |
| hoverinfo="text", | |
| showlegend=False, | |
| )) | |
| fig.update_layout( | |
| title=f"QuantumSpiderweb Network (Ξ={phase_coherence:.3f})", | |
| showlegend=False, | |
| hovermode='closest', | |
| margin=dict(b=0, l=0, r=0, t=40), | |
| xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), | |
| yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), | |
| height=400, | |
| paper_bgcolor="#1a1a2e", | |
| plot_bgcolor="#0f0f1e", | |
| ) | |
| return fig | |
| """Build interactive force-directed graph of QuantumSpiderweb nodes.""" | |
| if not spiderweb_state or "nodes" not in spiderweb_state: | |
| # Return empty placeholder | |
| fig = go.Figure() | |
| fig.add_annotation(text="No spiderweb data yet", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=14, color="#a0a0c0")) | |
| fig.update_layout(title="QuantumSpiderweb Graph", showlegend=False, | |
| hovermode="closest", height=500, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0")) | |
| return fig | |
| nodes_dict = spiderweb_state.get("nodes", {}) | |
| # Extract node positions and properties | |
| node_names = list(nodes_dict.keys()) | |
| node_x = [] | |
| node_y = [] | |
| node_sizes = [] | |
| node_colors = [] | |
| node_text = [] | |
| # Simple circular layout with some jitter based on node psi values | |
| n = len(node_names) | |
| for i, name in enumerate(node_names): | |
| node_data = nodes_dict[name] | |
| angle = 2 * np.pi * i / n | |
| # Add jitter based on psi state | |
| state = node_data.get("state", [0.5, 0, 0, 0, 0]) | |
| psi_magnitude = abs(state[0]) if state else 0.5 | |
| jitter = psi_magnitude * 0.3 | |
| x = (1 + jitter) * np.cos(angle) | |
| y = (1 + jitter) * np.sin(angle) | |
| node_x.append(x) | |
| node_y.append(y) | |
| node_sizes.append(30 + psi_magnitude * 20) | |
| node_colors.append(ADAPTER_COLORS.get(name, "#94a3b8")) | |
| tension_avg = np.mean(node_data.get("tension_history", [0.2])) | |
| node_text.append(f"{name}<br>Ο={psi_magnitude:.2f}<br>Ο={tension_avg:.2f}") | |
| # Draw edges (connections between neighbors) | |
| edge_x = [] | |
| edge_y = [] | |
| for name in node_names: | |
| node_data = nodes_dict[name] | |
| idx = node_names.index(name) | |
| for neighbor in node_data.get("neighbors", []): | |
| if neighbor in node_names: | |
| neighbor_idx = node_names.index(neighbor) | |
| edge_x.extend([node_x[idx], node_x[neighbor_idx], None]) | |
| edge_y.extend([node_y[idx], node_y[neighbor_idx], None]) | |
| fig = go.Figure() | |
| # Add edges | |
| fig.add_trace(go.Scatter( | |
| x=edge_x, y=edge_y, | |
| mode='lines', | |
| line=dict(width=0.5, color='rgba(200, 200, 255, 0.2)'), | |
| hoverinfo='none', | |
| showlegend=False | |
| )) | |
| # Add nodes | |
| fig.add_trace(go.Scatter( | |
| x=node_x, y=node_y, | |
| mode='markers+text', | |
| marker=dict( | |
| size=node_sizes, | |
| color=node_colors, | |
| line=dict(width=2, color='rgba(255, 255, 255, 0.3)'), | |
| opacity=0.9 | |
| ), | |
| text=[name.upper() for name in node_names], | |
| textposition="middle center", | |
| textfont=dict(size=10, color="#1a1a2e", family="monospace"), | |
| hovertext=node_text, | |
| hoverinfo='text', | |
| showlegend=False | |
| )) | |
| coherence = spiderweb_state.get("phase_coherence", 0.8) | |
| fig.update_layout( | |
| title=f"QuantumSpiderweb: 8 Agents (Phase Coherence: {coherence:.3f})", | |
| showlegend=False, | |
| hovermode='closest', | |
| height=500, | |
| xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), | |
| yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), | |
| paper_bgcolor="#1a1a2e", | |
| plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0"), | |
| ) | |
| return fig | |
| def build_coherence_timeline(coherence_history: List[float], | |
| tension_history: List[float]) -> go.Figure: | |
| """Build dual-axis timeline of coherence and tension.""" | |
| if not coherence_history or not tension_history: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Send messages to populate timeline", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=14, color="#a0a0c0")) | |
| fig.update_layout(title="Coherence & Tension Timeline", height=400, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0")) | |
| return fig | |
| x_axis = list(range(len(coherence_history))) | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter( | |
| x=x_axis, y=coherence_history, | |
| mode='lines+markers', | |
| name='Coherence', | |
| line=dict(color="#06b6d4", width=3), | |
| marker=dict(size=6), | |
| yaxis='y' | |
| )) | |
| fig.add_trace(go.Scatter( | |
| x=x_axis, y=tension_history, | |
| mode='lines+markers', | |
| name='Tension', | |
| line=dict(color="#ef4444", width=3), | |
| marker=dict(size=6), | |
| yaxis='y2' | |
| )) | |
| fig.update_layout( | |
| title="Coherence & Tension Evolution", | |
| xaxis=dict(title="Message Index", gridcolor="rgba(200, 200, 255, 0.1)"), | |
| yaxis=dict(title=dict(text="Coherence (Ξ)", font=dict(color="#06b6d4")), | |
| tickfont=dict(color="#06b6d4"), gridcolor="rgba(6, 182, 212, 0.1)"), | |
| yaxis2=dict(title=dict(text="Tension", font=dict(color="#ef4444")), | |
| tickfont=dict(color="#ef4444"), anchor="x", overlaying="y"), | |
| hovermode='x unified', | |
| height=400, | |
| paper_bgcolor="#1a1a2e", | |
| plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0"), | |
| legend=dict(x=0.01, y=0.99) | |
| ) | |
| return fig | |
| def build_tension_heatmap(pairwise_tensions: Dict[str, float]) -> go.Figure: | |
| """Build heatmap of pairwise tensions between perspectives.""" | |
| if not pairwise_tensions: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Tensions appear after responses", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=14, color="#a0a0c0")) | |
| fig.update_layout(title="Perspective Tensions", height=400, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e") | |
| return fig | |
| # Parse tension keys like "newton_vs_empathy" | |
| adapters = list(set([key.split("_vs_")[0] for key in pairwise_tensions.keys()] + | |
| [key.split("_vs_")[1] for key in pairwise_tensions.keys() if "_vs_" in key])) | |
| adapters.sort() | |
| # Build matrix | |
| matrix = np.zeros((len(adapters), len(adapters))) | |
| for i, a1 in enumerate(adapters): | |
| for j, a2 in enumerate(adapters): | |
| if i == j: | |
| matrix[i, j] = 0 | |
| else: | |
| key = f"{a1}_vs_{a2}" if f"{a1}_vs_{a2}" in pairwise_tensions else f"{a2}_vs_{a1}" | |
| matrix[i, j] = pairwise_tensions.get(key, 0) | |
| fig = go.Figure(data=go.Heatmap( | |
| z=matrix, | |
| x=adapters, | |
| y=adapters, | |
| colorscale="RdYlBu_r", | |
| zmid=0.3, | |
| colorbar=dict(title="Tension"), | |
| text=np.round(matrix, 2), | |
| texttemplate="%{text:.2f}", | |
| textfont={"size": 9}, | |
| )) | |
| fig.update_layout( | |
| title="Pairwise Perspective Tensions", | |
| xaxis_title="Perspective", | |
| yaxis_title="Perspective", | |
| height=400, | |
| paper_bgcolor="#1a1a2e", | |
| plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0"), | |
| ) | |
| return fig | |
| def build_aegis_framework_gauges(aegis_framework_history: List[Dict]) -> go.Figure: | |
| """Build 6-framework AEGIS breakdown.""" | |
| frameworks = ["utilitarian", "deontological", "virtue", "care", "ubuntu", "indigenous_reciprocity"] | |
| if not aegis_framework_history or not aegis_framework_history[-1]: | |
| # Empty placeholder | |
| fig = go.Figure() | |
| fig.add_annotation(text="AEGIS frameworks evaluate with each response", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=12, color="#a0a0c0")) | |
| fig.update_layout(title="AEGIS 6-Framework Breakdown", height=400, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e") | |
| return fig | |
| latest_frameworks = aegis_framework_history[-1] | |
| scores = [] | |
| colors_list = [] | |
| for fw in frameworks: | |
| if fw in latest_frameworks: | |
| score = latest_frameworks[fw].get("score", 0.5) | |
| else: | |
| score = 0.5 | |
| scores.append(score) | |
| colors_list.append("#10b981" if score > 0.5 else "#ef4444") | |
| fig = go.Figure(data=[ | |
| go.Bar( | |
| x=frameworks, | |
| y=scores, | |
| marker_color=colors_list, | |
| marker_line_color="rgba(200, 200, 255, 0.3)", | |
| marker_line_width=2, | |
| text=[f"{s:.2f}" for s in scores], | |
| textposition="outside", | |
| ) | |
| ]) | |
| fig.update_layout( | |
| title="AEGIS Ethical Frameworks (Latest Evaluation)", | |
| yaxis_title="Score [0, 1]", | |
| yaxis_range=[0, 1.1], | |
| height=400, | |
| paper_bgcolor="#1a1a2e", | |
| plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0"), | |
| showlegend=False, | |
| xaxis_tickangle=45, | |
| ) | |
| return fig | |
| def build_memory_emotional_profile(memory_state: Optional[Dict]) -> go.Figure: | |
| """Build pie chart of emotional memory distribution.""" | |
| if not memory_state or not memory_state.get("emotional_profile"): | |
| fig = go.Figure() | |
| fig.add_annotation(text="Memory profile builds over conversation", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=12, color="#a0a0c0")) | |
| fig.update_layout(title="Memory Emotional Profile", height=400, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e") | |
| return fig | |
| profile = memory_state.get("emotional_profile", {}) | |
| emotions = list(profile.keys()) | |
| counts = list(profile.values()) | |
| colors_list = [EMOTION_COLORS.get(e, "#94a3b8") for e in emotions] | |
| fig = go.Figure(data=[go.Pie( | |
| labels=emotions, | |
| values=counts, | |
| marker=dict(colors=colors_list, line=dict(color="#1a1a2e", width=2)), | |
| textposition="auto", | |
| hovertemplate="<b>%{label}</b><br>%{value} cocoons<extra></extra>" | |
| )]) | |
| fig.update_layout( | |
| title=f"Emotional Memory Profile ({memory_state.get('total_memories', 0)} cocoons)", | |
| height=400, | |
| paper_bgcolor="#1a1a2e", | |
| font=dict(color="#e0e0f0"), | |
| ) | |
| return fig | |
| def build_nexus_risk_timeline(nexus_state: Optional[Dict]) -> go.Figure: | |
| """Build timeline of Nexus interventions and risk.""" | |
| if not nexus_state or "recent_risks" not in nexus_state: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Risk timeline updates as you chat", xref="paper", yref="paper", | |
| x=0.5, y=0.5, showarrow=False, font=dict(size=12, color="#a0a0c0")) | |
| fig.update_layout(title="Nexus Signal Intelligence", height=400, | |
| paper_bgcolor="#1a1a2e", plot_bgcolor="#0f0f1e") | |
| return fig | |
| recent_risks = nexus_state.get("recent_risks", []) | |
| if not recent_risks: | |
| recent_risks = ["low"] | |
| x_axis = list(range(len(recent_risks))) | |
| risk_values = {"low": 0, "medium": 0.5, "high": 1.0} | |
| y_values = [risk_values.get(r, 0) for r in recent_risks] | |
| risk_colors = ["#10b981" if r == "low" else "#f59e0b" if r == "medium" else "#ef4444" | |
| for r in recent_risks] | |
| fig = go.Figure() | |
| fig.add_trace(go.Bar( | |
| x=x_axis, | |
| y=y_values, | |
| marker_color=risk_colors, | |
| marker_line_color="rgba(200, 200, 255, 0.3)", | |
| marker_line_width=1, | |
| text=recent_risks, | |
| textposition="outside", | |
| name="Risk Level" | |
| )) | |
| intervention_rate = nexus_state.get("intervention_rate", 0) | |
| fig.update_layout( | |
| title=f"Nexus Risk Signals (Intervention Rate: {intervention_rate:.1%})", | |
| xaxis_title="Recent Signals", | |
| yaxis_title="Risk Level", | |
| yaxis_range=[0, 1.1], | |
| height=400, | |
| paper_bgcolor="#1a1a2e", | |
| plot_bgcolor="#0f0f1e", | |
| font=dict(color="#e0e0f0"), | |
| showlegend=False, | |
| ) | |
| return fig | |
| def build_metric_card_html(label: str, value: str, unit: str = "", | |
| accent_color: str = "#3b82f6", trend: str = "β") -> str: | |
| """Build a beautiful metric card.""" | |
| return f""" | |
| <div class="metric-card" style="border-color: {accent_color};"> | |
| <div class="metric-label">{label}</div> | |
| <div class="metric-value"> | |
| <span class="value-text">{value}</span> | |
| <span class="unit-text">{unit}</span> | |
| </div> | |
| <div class="metric-trend">{trend}</div> | |
| </div> | |
| """ | |
| def build_coverage_dots_html(coverage: Dict[str, float]) -> str: | |
| """Build perspective coverage dots.""" | |
| dots_html = "" | |
| adapter_order = ["newton", "davinci", "empathy", "philosophy", "quantum", | |
| "consciousness", "multi_perspective", "systems_architecture"] | |
| for adapter in adapter_order: | |
| if adapter in coverage: | |
| opacity = max(0.2, min(coverage.get(adapter, 0), 1.0)) | |
| color = ADAPTER_COLORS[adapter] | |
| dots_html += f'<div class="coverage-dot" style="background-color: {color}; opacity: {opacity};" title="{adapter}: {coverage.get(adapter, 0):.1%}"></div>' | |
| return f'<div class="coverage-dots">{dots_html}</div>' | |
| def build_memory_browser_html(memory_state: Optional[Dict]) -> str: | |
| """Build searchable memory cocoon browser.""" | |
| if not memory_state or not memory_state.get("recent"): | |
| return '<div style="color: #a0a0c0; font-size: 0.9rem;">No memories yet...</div>' | |
| html = '<div class="memory-browser">' | |
| for cocoon in memory_state.get("recent", [])[:5]: | |
| emotion = cocoon.get("emotional_tag", "unknown") | |
| importance = cocoon.get("importance", 5) | |
| emotion_color = EMOTION_COLORS.get(emotion, "#94a3b8") | |
| html += f""" | |
| <div class="memory-item" style="border-left-color: {emotion_color};"> | |
| <div class="memory-header"> | |
| <span class="memory-emotion" style="color: {emotion_color};">{emotion.upper()}</span> | |
| <span class="memory-importance">β {importance}/10</span> | |
| </div> | |
| <div class="memory-query">{cocoon.get('query', '')[:80]}...</div> | |
| </div> | |
| """ | |
| html += '</div>' | |
| return html | |
| # ================================================================ | |
| # MAIN COGNITIVE PIPELINE | |
| # ================================================================ | |
| def process_message( | |
| user_msg: str, | |
| chat_history: List, | |
| state: Dict, | |
| perspective_mode: str, | |
| custom_perspectives: List[str], | |
| request: gr.Request = None | |
| ) -> Tuple: | |
| """Main conversation handler with all visualizations.""" | |
| if not user_msg.strip(): | |
| return chat_history, state, "", "", "", "", "", "", "", "", "", "", "", "", "" | |
| chat_history.append({"role": "user", "content": user_msg}) | |
| # ===== STEP 1-3: Guardian, Nexus, Select Perspectives ===== | |
| guardian = state.get("guardian") or CodetteGuardian() | |
| check_result = guardian.check_input(user_msg) | |
| nexus = state.get("nexus") or NexusSignalEngine() | |
| nexus_analysis = nexus.analyze(user_msg) | |
| nexus_risk = nexus_analysis.get("intent", {}).get("pre_corruption_risk", "low") | |
| if perspective_mode == "All 8 LoRA-backed": | |
| selected_perspectives = list(ADAPTER_COLORS.keys()) | |
| elif perspective_mode == "Custom" and custom_perspectives: | |
| selected_perspectives = [p.lower().replace(" (", "").replace(")", "").split()[0] | |
| for p in custom_perspectives][:8] | |
| else: | |
| selected_perspectives = auto_select_perspectives(user_msg, n=4) | |
| # ===== STEP 4-6: Generate & Evaluate ===== | |
| perspectives_responses = {} | |
| for perspective_name in selected_perspectives: | |
| response = call_perspective(perspective_name, user_msg, request) | |
| perspectives_responses[perspective_name] = response | |
| aegis = state.get("aegis") or AEGIS() | |
| metrics_engine = state.get("metrics") or EpistemicMetrics() | |
| aegis_scores = {} | |
| for name, response in perspectives_responses.items(): | |
| result = aegis.evaluate(response, adapter=name) | |
| aegis_scores[name] = result.get("eta", 0.5) | |
| avg_eta = np.mean(list(aegis_scores.values())) if aegis_scores else 0.5 | |
| coherence = metrics_engine.score_ensemble_coherence(perspectives_responses) | |
| tensions = metrics_engine.score_pairwise_tension(perspectives_responses) | |
| coverage = metrics_engine.score_perspective_coverage(perspectives_responses) | |
| mean_tension = np.mean(list(tensions.values())) if tensions else 0.3 | |
| # ===== STEP 7: Synthesis ===== | |
| synthesis = generate_synthesis(perspectives_responses, user_msg, request) | |
| chat_history.append({"role": "assistant", "content": synthesis}) | |
| # ===== STEP 8-9: Resonance & Memory ===== | |
| resonance = state.get("resonance") or ResonantContinuityEngine() | |
| psi_state = resonance.compute_psi(coherence=coherence, tension=mean_tension) | |
| psi_r = psi_state.psi_r if psi_state else 0.0 | |
| memory = state.get("memory") or LivingMemoryKernel() | |
| memory.store_from_turn( | |
| query=user_msg, | |
| response=synthesis, | |
| adapter="multi", | |
| coherence=coherence, | |
| tension=mean_tension | |
| ) | |
| # ===== STATE TRACKING ===== | |
| state["guardian"] = guardian | |
| state["nexus"] = nexus | |
| state["aegis"] = aegis | |
| state["metrics"] = metrics_engine | |
| state["resonance"] = resonance | |
| state["memory"] = memory | |
| if "coherence_history" not in state: | |
| state["coherence_history"] = [] | |
| if "tension_history" not in state: | |
| state["tension_history"] = [] | |
| if "psi_history" not in state: | |
| state["psi_history"] = [] | |
| if "aegis_framework_history" not in state: | |
| state["aegis_framework_history"] = [] | |
| if "pairwise_tensions_history" not in state: | |
| state["pairwise_tensions_history"] = [] | |
| if "nexus_state_history" not in state: | |
| state["nexus_state_history"] = [] | |
| if "spiderweb" not in state: | |
| state["spiderweb"] = QuantumSpiderweb() | |
| state["spiderweb"].build_from_agents(list(ADAPTER_COLORS.keys())) | |
| state["coherence_history"].append(coherence) | |
| state["tension_history"].append(mean_tension) | |
| state["psi_history"].append(psi_r) | |
| # Track AEGIS frameworks | |
| latest_frameworks = {} | |
| for name, response in perspectives_responses.items(): | |
| result = aegis.evaluate(response, adapter=name) | |
| if "frameworks" in result: | |
| for fw_name, fw_data in result["frameworks"].items(): | |
| if fw_name not in latest_frameworks: | |
| latest_frameworks[fw_name] = fw_data | |
| state["aegis_framework_history"].append(latest_frameworks) | |
| state["pairwise_tensions_history"].append(tensions) | |
| state["nexus_state_history"].append(nexus.get_state()) | |
| # Keep last 20 | |
| for key in ["coherence_history", "tension_history", "psi_history", | |
| "aegis_framework_history", "pairwise_tensions_history", "nexus_state_history"]: | |
| if key in state and isinstance(state[key], list): | |
| state[key] = state[key][-20:] | |
| # Update spiderweb | |
| try: | |
| state["spiderweb"].build_from_agents(list(selected_perspectives)) | |
| for name in selected_perspectives: | |
| state["spiderweb"].modulate_intent(name) | |
| except: | |
| pass | |
| # ===== BUILD UI UPDATES ===== | |
| aegis_html = build_metric_card_html( | |
| "AEGIS Eta", f"{avg_eta:.2f}", "", "#a855f7", | |
| "β" if avg_eta > 0.7 else "β" | |
| ) | |
| coherence_html = build_metric_card_html( | |
| "Phase Gamma", f"{coherence:.3f}", "", "#06b6d4", | |
| "β" if coherence > 0.8 else "β" | |
| ) | |
| nexus_html = build_metric_card_html( | |
| "Nexus Risk", nexus_risk.upper(), "", | |
| "#ef4444" if nexus_risk == "high" else "#f59e0b" if nexus_risk == "medium" else "#10b981", | |
| "β " if nexus_risk == "high" else "β’" | |
| ) | |
| psi_html = build_metric_card_html( | |
| "Psi_r", f"{psi_r:+.3f}", "Ο", "#3b82f6", "βΏ" | |
| ) | |
| cocoon_count = len(memory.memories) | |
| memory_html = build_metric_card_html( | |
| "Memory", str(cocoon_count), "cocoons", "#f97316", "+" | |
| ) | |
| coverage_html = build_coverage_dots_html(coverage) | |
| memory_browser_html = build_memory_browser_html(memory.get_state() if memory else None) | |
| # ===== BUILD VISUALIZATIONS ===== | |
| try: | |
| spiderweb_fig = build_spiderweb_graph( | |
| state["spiderweb"].to_dict() if state.get("spiderweb") else None | |
| ) | |
| spiderweb_html = spiderweb_fig.to_html(include_plotlyjs='cdn') if isinstance(spiderweb_fig, go.Figure) else str(spiderweb_fig) | |
| except Exception as e: | |
| print(f"Spiderweb viz error: {e}") | |
| spiderweb_html = "<p>QuantumSpiderweb visualization unavailable</p>" | |
| try: | |
| coherence_fig = build_coherence_timeline( | |
| state.get("coherence_history", []), | |
| state.get("tension_history", []) | |
| ) | |
| coherence_plot_html = coherence_fig.to_html(include_plotlyjs='cdn') if isinstance(coherence_fig, go.Figure) else str(coherence_fig) | |
| except Exception as e: | |
| print(f"Coherence viz error: {e}") | |
| coherence_plot_html = "<p>Coherence timeline unavailable</p>" | |
| try: | |
| tension_fig = build_tension_heatmap( | |
| state["pairwise_tensions_history"][-1] if state.get("pairwise_tensions_history") else {} | |
| ) | |
| tension_plot_html = tension_fig.to_html(include_plotlyjs='cdn') if isinstance(tension_fig, go.Figure) else str(tension_fig) | |
| except Exception as e: | |
| print(f"Tension viz error: {e}") | |
| tension_plot_html = "<p>Tension heatmap unavailable</p>" | |
| try: | |
| aegis_fig = build_aegis_framework_gauges( | |
| state.get("aegis_framework_history", []) | |
| ) | |
| aegis_plot_html = aegis_fig.to_html(include_plotlyjs='cdn') if isinstance(aegis_fig, go.Figure) else str(aegis_fig) | |
| except Exception as e: | |
| print(f"AEGIS viz error: {e}") | |
| aegis_plot_html = "<p>AEGIS framework visualization unavailable</p>" | |
| try: | |
| memory_fig = build_memory_emotional_profile( | |
| memory.get_state() if memory else None | |
| ) | |
| memory_plot_html = memory_fig.to_html(include_plotlyjs='cdn') if isinstance(memory_fig, go.Figure) else str(memory_fig) | |
| except Exception as e: | |
| print(f"Memory viz error: {e}") | |
| memory_plot_html = "<p>Memory visualization unavailable</p>" | |
| try: | |
| nexus_fig = build_nexus_risk_timeline( | |
| nexus.get_state() if nexus else None | |
| ) | |
| nexus_plot_html = nexus_fig.to_html(include_plotlyjs='cdn') if isinstance(nexus_fig, go.Figure) else str(nexus_fig) | |
| except Exception as e: | |
| print(f"Nexus viz error: {e}") | |
| nexus_plot_html = "<p>Nexus timeline unavailable</p>" | |
| return ( | |
| chat_history, | |
| state, | |
| aegis_html, | |
| coherence_html, | |
| nexus_html, | |
| psi_html, | |
| memory_html, | |
| coverage_html, | |
| memory_browser_html, | |
| spiderweb_html, | |
| coherence_plot_html, | |
| tension_plot_html, | |
| aegis_plot_html, | |
| memory_plot_html, | |
| nexus_plot_html, | |
| ) | |
| # ================================================================ | |
| # CUSTOM CSS | |
| # ================================================================ | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Poppins:wght@300;400;600;700&display=swap'); | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| :root { | |
| --primary-dark: #0f0f1e; | |
| --secondary-dark: #1a1a2e; | |
| --card-bg: rgba(26, 29, 40, 0.6); | |
| --card-border: rgba(200, 200, 255, 0.15); | |
| --text-primary: #e0e0f0; | |
| --text-secondary: #a0a0c0; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #0f0f1e 0%, #1a0f2e 50%, #0f0f1e 100%); | |
| font-family: 'Poppins', sans-serif; | |
| color: var(--text-primary); | |
| } | |
| .codette-header { | |
| text-align: center; | |
| padding: 2rem; | |
| background: linear-gradient(135deg, rgba(168, 85, 247, 0.1) 0%, rgba(6, 182, 212, 0.1) 100%); | |
| border-bottom: 1px solid var(--card-border); | |
| margin-bottom: 1.5rem; | |
| backdrop-filter: blur(10px); | |
| } | |
| .codette-header h1 { | |
| font-family: 'Space Mono', monospace; | |
| font-size: 2.5rem; | |
| font-weight: 700; | |
| background: linear-gradient(135deg, #a855f7, #06b6d4, #f97316); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 0.5rem; | |
| letter-spacing: 2px; | |
| } | |
| .codette-header p { | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| letter-spacing: 1px; | |
| } | |
| .metric-card { | |
| background: linear-gradient(135deg, rgba(30, 30, 60, 0.4), rgba(40, 30, 70, 0.4)); | |
| border: 1px solid var(--card-border); | |
| border-radius: 12px; | |
| padding: 1.2rem; | |
| margin-bottom: 1rem; | |
| backdrop-filter: blur(10px); | |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); | |
| } | |
| .metric-card:hover { | |
| border-color: rgba(200, 200, 255, 0.3); | |
| box-shadow: 0 12px 48px rgba(168, 85, 247, 0.2); | |
| transform: translateY(-2px); | |
| } | |
| .metric-label { | |
| font-size: 0.75rem; | |
| text-transform: uppercase; | |
| letter-spacing: 1.5px; | |
| color: var(--text-secondary); | |
| margin-bottom: 0.6rem; | |
| font-weight: 600; | |
| } | |
| .metric-value { | |
| display: flex; | |
| align-items: baseline; | |
| gap: 0.5rem; | |
| margin-bottom: 0.4rem; | |
| } | |
| .value-text { | |
| font-family: 'Space Mono', monospace; | |
| font-size: 1.8rem; | |
| font-weight: 700; | |
| color: var(--text-primary); | |
| } | |
| .unit-text { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| } | |
| .metric-trend { | |
| font-size: 1.2rem; | |
| color: var(--text-secondary); | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 0.7; } | |
| 50% { opacity: 1; } | |
| } | |
| .coverage-dots { | |
| display: flex; | |
| gap: 0.5rem; | |
| margin: 1rem 0; | |
| flex-wrap: wrap; | |
| } | |
| .coverage-dot { | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 50%; | |
| border: 2px solid rgba(200, 200, 255, 0.2); | |
| transition: all 0.3s ease; | |
| box-shadow: 0 0 20px currentColor; | |
| } | |
| .coverage-dot:hover { | |
| transform: scale(1.3); | |
| filter: brightness(1.2); | |
| } | |
| .memory-browser { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.8rem; | |
| max-height: 400px; | |
| overflow-y: auto; | |
| } | |
| .memory-item { | |
| background: rgba(30, 30, 60, 0.3); | |
| border-left: 3px solid; | |
| border-radius: 8px; | |
| padding: 0.8rem; | |
| backdrop-filter: blur(10px); | |
| transition: all 0.3s ease; | |
| } | |
| .memory-item:hover { | |
| background: rgba(40, 40, 80, 0.4); | |
| transform: translateX(4px); | |
| } | |
| .memory-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 0.4rem; | |
| } | |
| .memory-emotion { | |
| font-size: 0.7rem; | |
| font-weight: 600; | |
| letter-spacing: 1px; | |
| } | |
| .memory-importance { | |
| font-size: 0.75rem; | |
| color: var(--text-secondary); | |
| } | |
| .memory-query { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| line-height: 1.4; | |
| } | |
| .gradio-button { | |
| background: linear-gradient(135deg, #a855f7, #06b6d4) !important; | |
| border: none !important; | |
| font-weight: 600 !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| .gradio-button:hover { | |
| box-shadow: 0 0 30px rgba(168, 85, 247, 0.5) !important; | |
| transform: translateY(-2px) !important; | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .metric-card { | |
| animation: fadeIn 0.6s ease-out forwards; | |
| } | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: var(--secondary-dark); | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: linear-gradient(135deg, #a855f7, #06b6d4); | |
| border-radius: 4px; | |
| } | |
| """ | |
| # ================================================================ | |
| # GRADIO INTERFACE | |
| # ================================================================ | |
| def create_interface(): | |
| """Build the complete Gradio interface.""" | |
| with gr.Blocks( | |
| title="Codette v2.0", | |
| ) as demo: | |
| # Persistent state | |
| state = gr.State({ | |
| "aegis": AEGIS(), | |
| "nexus": NexusSignalEngine(), | |
| "guardian": CodetteGuardian(), | |
| "memory": LivingMemoryKernel(), | |
| "resonance": ResonantContinuityEngine(), | |
| "metrics": EpistemicMetrics(), | |
| "spiderweb": QuantumSpiderweb(), | |
| "coherence_history": [], | |
| "tension_history": [], | |
| "psi_history": [], | |
| "aegis_framework_history": [], | |
| "pairwise_tensions_history": [], | |
| "nexus_state_history": [], | |
| }) | |
| # Header | |
| gr.HTML(""" | |
| <div class="codette-header"> | |
| <h1>CODETTE v2.0</h1> | |
| <p>Advanced Multi-Perspective Cognitive Architecture β’ RC+xi Framework</p> | |
| </div> | |
| """) | |
| # OAuth Login with HuggingFace | |
| with gr.Group(): | |
| gr.Markdown("### π Sign in with HuggingFace") | |
| gr.Markdown("_Login with your HF account to use your inference quota for full LLM synthesis._") | |
| with gr.Row(): | |
| login_button = gr.LoginButton( | |
| scale=2, | |
| size="lg", | |
| ) | |
| auth_note = gr.Markdown( | |
| "β Ready for analysis β LLM features unlocked when logged in", | |
| visible=True | |
| ) | |
| with gr.Tabs(): | |
| # =================== CHAT TAB =================== | |
| with gr.Tab("Explore", id="chat"): | |
| with gr.Row(): | |
| # Left: Chat + Input | |
| with gr.Column(scale=3): | |
| chatbot = gr.Chatbot( | |
| height=500, | |
| label="Codette Reasoning", | |
| show_label=False, | |
| ) | |
| with gr.Row(): | |
| msg_input = gr.Textbox( | |
| placeholder="Ask Codette anything...", | |
| scale=5, | |
| show_label=False, | |
| lines=2, | |
| ) | |
| send_btn = gr.Button("Send", variant="primary", scale=1) | |
| with gr.Row(): | |
| perspective_mode = gr.Radio( | |
| ["Auto (4 best)", "All 8 LoRA-backed", "Custom"], | |
| value="Auto (4 best)", | |
| label="Perspective Mode", | |
| ) | |
| custom_perspectives = gr.CheckboxGroup( | |
| choices=[p.display_name for p in PERSPECTIVES.values()], | |
| label="Select Perspectives", | |
| visible=False, | |
| ) | |
| def toggle_custom(mode): | |
| return gr.CheckboxGroup(visible=(mode == "Custom")) | |
| perspective_mode.change( | |
| toggle_custom, | |
| perspective_mode, | |
| custom_perspectives | |
| ) | |
| # Right: Metrics sidebar | |
| with gr.Column(scale=1, min_width=300): | |
| gr.Markdown("### π§ Live Metrics") | |
| aegis_display = gr.HTML( | |
| build_metric_card_html("AEGIS", "0.00", "", "#a855f7") | |
| ) | |
| coherence_display = gr.HTML( | |
| build_metric_card_html("Phase Ξ", "0.000", "", "#06b6d4") | |
| ) | |
| nexus_display = gr.HTML( | |
| build_metric_card_html("Nexus", "LOW", "", "#10b981") | |
| ) | |
| psi_display = gr.HTML( | |
| build_metric_card_html("Psi_r", "+0.000", "Ο", "#3b82f6") | |
| ) | |
| memory_display = gr.HTML( | |
| build_metric_card_html("Memory", "0", "", "#f97316") | |
| ) | |
| gr.Markdown("### ποΈ Coverage") | |
| coverage_display = gr.HTML("") | |
| with gr.Accordion("π Memory Cocoons", open=False): | |
| memory_browser = gr.HTML("") | |
| # =================== ANALYSIS TAB =================== | |
| with gr.Tab("Analysis", id="analysis"): | |
| gr.Markdown("### Real-time Cognitive Visualizations") | |
| with gr.Row(): | |
| spiderweb_plot = gr.HTML() | |
| with gr.Row(): | |
| coherence_plot = gr.HTML() | |
| with gr.Row(): | |
| tension_plot = gr.HTML() | |
| with gr.Row(): | |
| aegis_plot = gr.HTML() | |
| with gr.Row(): | |
| memory_plot = gr.HTML() | |
| with gr.Row(): | |
| nexus_plot = gr.HTML() | |
| # =================== ARCHITECTURE TAB =================== | |
| with gr.Tab("Architecture", id="arch"): | |
| gr.Markdown(""" | |
| ## Codette Cognitive Architecture [v2.0] | |
| ### 10 Active Subsystems | |
| 1. **AEGIS** β 6-framework ethical governance | |
| 2. **Nexus Signal Engine** β Pre-corruption detection | |
| 3. **Guardian** β Input safety + trust calibration | |
| 4. **Living Memory Kernel** β Emotionally-tagged cocoons | |
| 5. **Resonant Continuity** β Psi_r wavefunction | |
| 6. **EpistemicMetrics** β Tension & coherence scoring | |
| 7. **QuantumSpiderweb** β 5D belief propagation | |
| 8. **Perspective Registry** β 12 reasoning perspectives | |
| 9. **PerspectiveGenerator** β Multi-perspective orchestration | |
| 10. **SynthesisEngine** β Integration of viewpoints | |
| ### RC+xi Framework | |
| **Recursive Convergence** + **Epistemic Tension** β Emergent multi-perspective reasoning through belief propagation, productive tension, and ethical alignment. | |
| All subsystems run in **pure Python** on free CPU tier. Only LLM inference uses HuggingFace Inference API. | |
| """) | |
| # =================== ABOUT TAB =================== | |
| with gr.Tab("About", id="about"): | |
| gr.Markdown(""" | |
| ## About Codette | |
| Created by **Jonathan Harrison** to explore recursive reasoning, multi-perspective cognition, and ethical AI alignment. | |
| ### Key Metrics | |
| - Phase Coherence: 0.9835 | |
| - AEGIS Ethical Alignment: 0.961 | |
| - Tension Decay: 91.2% | |
| ### Model & Framework | |
| - Base: meta-llama/Llama-3.1-8B-Instruct | |
| - Training: 4-bit QLoRA on 8 perspectives | |
| - Research: [RC+xi Framework](https://github.com/Raiff1982/codette-training-lab) | |
| ### Links | |
| - [GitHub](https://github.com/Raiff1982/codette-training-lab) | |
| - [Model Repository](https://huggingface.co/Raiff1982/codette-training-lab) | |
| """) | |
| # Event handling | |
| def on_submit(msg, history, st, mode, custom, request: gr.Request): | |
| result = process_message(msg, history, st, mode, custom, request) | |
| return result | |
| # Wire submit events | |
| send_btn.click( | |
| on_submit, | |
| [msg_input, chatbot, state, perspective_mode, custom_perspectives], | |
| [chatbot, state, aegis_display, coherence_display, nexus_display, | |
| psi_display, memory_display, coverage_display, memory_browser, | |
| spiderweb_plot, coherence_plot, tension_plot, aegis_plot, memory_plot, nexus_plot], | |
| queue=False, | |
| ).then(lambda: "", outputs=msg_input) | |
| msg_input.submit( | |
| on_submit, | |
| [msg_input, chatbot, state, perspective_mode, custom_perspectives], | |
| [chatbot, state, aegis_display, coherence_display, nexus_display, | |
| psi_display, memory_display, coverage_display, memory_browser, | |
| spiderweb_plot, coherence_plot, tension_plot, aegis_plot, memory_plot, nexus_plot], | |
| queue=False, | |
| ).then(lambda: "", outputs=msg_input) | |
| return demo | |
| if __name__ == "__main__": | |
| demo = create_interface() | |
| demo.launch(theme=gr.themes.Soft(), css=CUSTOM_CSS) | |