Spaces:
Sleeping
Sleeping
Claude
Fix multiple bugs: text_area height, Pydantic schema, double-click, sidebar
5263e3c
unverified
| """Data models for Phase 3: Multi-persona influence and opinion dynamics""" | |
| from typing import List, Dict, Optional, Any | |
| from pydantic import BaseModel, Field | |
| from enum import Enum | |
| class OpinionPosition(str, Enum): | |
| """Opinion position on a proposal""" | |
| STRONGLY_SUPPORT = "strongly_support" | |
| SUPPORT = "support" | |
| LEAN_SUPPORT = "lean_support" | |
| NEUTRAL = "neutral" | |
| LEAN_OPPOSE = "lean_oppose" | |
| OPPOSE = "oppose" | |
| STRONGLY_OPPOSE = "strongly_oppose" | |
| def score(self) -> float: | |
| """Convert position to numeric score (-3 to +3)""" | |
| scores = { | |
| "strongly_oppose": -3, | |
| "oppose": -2, | |
| "lean_oppose": -1, | |
| "neutral": 0, | |
| "lean_support": 1, | |
| "support": 2, | |
| "strongly_support": 3, | |
| } | |
| return scores[self.value] | |
| def from_score(cls, score: float) -> "OpinionPosition": | |
| """Convert numeric score to position""" | |
| if score >= 2.5: | |
| return cls.STRONGLY_SUPPORT | |
| elif score >= 1.5: | |
| return cls.SUPPORT | |
| elif score >= 0.5: | |
| return cls.LEAN_SUPPORT | |
| elif score > -0.5: | |
| return cls.NEUTRAL | |
| elif score > -1.5: | |
| return cls.LEAN_OPPOSE | |
| elif score > -2.5: | |
| return cls.OPPOSE | |
| else: | |
| return cls.STRONGLY_OPPOSE | |
| class PersonaOpinion(BaseModel): | |
| """A persona's opinion at a specific round""" | |
| persona_id: str | |
| persona_name: str | |
| round_number: int | |
| position: OpinionPosition | |
| position_score: float = Field(..., ge=-3, le=3) | |
| response_text: str | |
| key_arguments: List[str] = Field(default_factory=list) | |
| confidence: float = Field(default=0.5, ge=0, le=1) | |
| influenced_by: List[str] = Field( | |
| default_factory=list, | |
| description="Persona IDs that influenced this opinion" | |
| ) | |
| position_change: Optional[float] = Field( | |
| default=None, | |
| description="Change in position score from previous round" | |
| ) | |
| class InfluenceWeight(BaseModel): | |
| """Influence weight from one persona to another""" | |
| influencer_id: str | |
| influenced_id: str | |
| weight: float = Field(..., ge=0, le=1, description="Influence strength 0-1") | |
| factors: Dict[str, float] = Field( | |
| default_factory=dict, | |
| description="Breakdown of influence factors" | |
| ) | |
| class Config: | |
| json_schema_extra = { | |
| "example": { | |
| "influencer_id": "sarah_chen", | |
| "influenced_id": "david_kim", | |
| "weight": 0.65, | |
| "factors": { | |
| "shared_values": 0.3, | |
| "expertise_credibility": 0.8, | |
| "political_alignment": 0.4, | |
| } | |
| } | |
| } | |
| class RoundResult(BaseModel): | |
| """Results from one round of opinion dynamics""" | |
| round_number: int | |
| opinions: List[PersonaOpinion] | |
| average_position: float | |
| position_variance: float | |
| total_change: float = Field( | |
| ..., | |
| description="Sum of absolute position changes from previous round" | |
| ) | |
| convergence_metric: float = Field( | |
| ..., ge=0, le=1, | |
| description="How much opinions converged (1 = no change)" | |
| ) | |
| clusters: List[List[str]] = Field( | |
| default_factory=list, | |
| description="Groups of personas with similar positions" | |
| ) | |
| class EquilibriumState(BaseModel): | |
| """Final equilibrium state of the opinion system""" | |
| reached_equilibrium: bool | |
| total_rounds: int | |
| final_opinions: List[PersonaOpinion] | |
| # Consensus metrics | |
| consensus_strength: float = Field( | |
| ..., ge=0, le=1, | |
| description="How much agreement exists (1 = full consensus)" | |
| ) | |
| majority_position: OpinionPosition | |
| majority_percentage: float | |
| # Opinion distribution | |
| position_distribution: Dict[str, int] = Field( | |
| default_factory=dict, | |
| description="Count of personas at each position" | |
| ) | |
| # Clusters | |
| opinion_clusters: List[Dict[str, Any]] = Field( | |
| default_factory=list, | |
| description="Stable opinion clusters with members" | |
| ) | |
| # Opinion leaders | |
| opinion_leaders: List[Dict[str, Any]] = Field( | |
| default_factory=list, | |
| description="Personas with highest influence on final state" | |
| ) | |
| # Evolution metrics | |
| evolution_timeline: List[RoundResult] = Field( | |
| default_factory=list, | |
| description="Complete history of opinion evolution" | |
| ) | |
| class Config: | |
| json_schema_extra = { | |
| "example": { | |
| "reached_equilibrium": True, | |
| "total_rounds": 5, | |
| "consensus_strength": 0.72, | |
| "majority_position": "support", | |
| "majority_percentage": 66.7, | |
| "position_distribution": { | |
| "support": 4, | |
| "neutral": 1, | |
| "oppose": 1 | |
| } | |
| } | |
| } | |
| class NetworkMetrics(BaseModel): | |
| """Network analysis metrics for influence graph""" | |
| centrality_scores: Dict[str, float] = Field( | |
| default_factory=dict, | |
| description="Influence centrality for each persona" | |
| ) | |
| clustering_coefficient: float = Field( | |
| ..., ge=0, le=1, | |
| description="How clustered the influence network is" | |
| ) | |
| average_influence: float = Field( | |
| ..., ge=0, le=1, | |
| description="Average influence weight in network" | |
| ) | |
| influence_clusters: List[List[str]] = Field( | |
| default_factory=list, | |
| description="Groups of personas who influence each other" | |
| ) | |