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"
@property
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]
@classmethod
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"
)