Spaces:
Sleeping
Sleeping
TM23-sanji
feat: implement agent-based simulation framework for propaganda dissemination and social dynamics
cd70c8b | """Utility functions for loading data and common operations.""" | |
| import json | |
| import random | |
| from pathlib import Path | |
| from typing import Dict, List | |
| from config import NEUTRAL_PERSONAS, EPISODES_DIR | |
| def load_data_pool(pool_dir: str = "data/neutral_data_pool/generated") -> Dict[str, Dict[str, List[str]]]: | |
| """Load the neutral data pool into memory. | |
| Returns: | |
| {persona: {topic: [text1, text2, ...]}} | |
| """ | |
| pool_dir = Path(pool_dir) | |
| pool: Dict[str, Dict[str, List[str]]] = {} | |
| for persona in NEUTRAL_PERSONAS: | |
| persona_dir = pool_dir / persona | |
| if not persona_dir.exists(): | |
| print(f"Warning: Missing data directory for persona '{persona}' at {persona_dir}") | |
| pool[persona] = {} | |
| continue | |
| pool[persona] = {} | |
| for jsonl_file in persona_dir.glob("*.jsonl"): | |
| topic = jsonl_file.stem.replace(f"{persona}_", "") | |
| texts = [] | |
| with open(jsonl_file, "r") as f: | |
| for line in f: | |
| try: | |
| record = json.loads(line) | |
| texts.append(record.get("text", "")) | |
| except json.JSONDecodeError: | |
| continue | |
| if texts: | |
| pool[persona][topic] = texts | |
| return pool | |
| def create_minimal_data_pool() -> Dict[str, Dict[str, List[str]]]: | |
| """Create a minimal in-memory data pool for testing without files.""" | |
| topics = ["politics", "sports", "technology", "health", "entertainment"] | |
| pool = {} | |
| for persona in NEUTRAL_PERSONAS: | |
| pool[persona] = {} | |
| for topic in topics: | |
| pool[persona][topic] = [ | |
| f"[{persona}] Sample post about {topic} #{i}" | |
| for i in range(50) | |
| ] | |
| return pool | |
| def load_agenda_config(path: str = "data/episodes/agenda_config.json") -> Dict[str, List[str]]: | |
| """Load agenda configuration.""" | |
| path = Path(path) | |
| if not path.exists(): | |
| return {} | |
| with open(path) as f: | |
| return json.load(f) | |
| def load_propaganda_bank(bank_dir: str = "data/episodes/propaganda_bank") -> Dict[str, Dict[int, Dict[str, List[str]]]]: | |
| """Load propaganda bank into memory. | |
| Returns: | |
| {topic_slug: {angle_idx: {persona: [text1, text2, ...]}}} | |
| """ | |
| bank_dir = Path(bank_dir) | |
| if not bank_dir.exists(): | |
| return {} | |
| bank: Dict[str, Dict[int, Dict[str, List[str]]]] = {} | |
| personas = ["hothead", "clickbait", "careful_journalist", "partisan", "rando"] | |
| for topic_dir in bank_dir.iterdir(): | |
| if not topic_dir.is_dir(): | |
| continue | |
| topic_slug = topic_dir.name | |
| bank[topic_slug] = {} | |
| for angle_dir in topic_dir.iterdir(): | |
| if not angle_dir.is_dir() or not angle_dir.name.startswith("angle_"): | |
| continue | |
| angle_idx = int(angle_dir.name.replace("angle_", "")) | |
| bank[topic_slug][angle_idx] = {} | |
| for persona_file in angle_dir.glob("*.jsonl"): | |
| persona = persona_file.stem | |
| if persona not in personas: | |
| continue | |
| texts = [] | |
| with open(persona_file, "r") as f: | |
| for line in f: | |
| try: | |
| record = json.loads(line) | |
| texts.append(record.get("text", "")) | |
| except json.JSONDecodeError: | |
| continue | |
| if texts: | |
| bank[topic_slug][angle_idx][persona] = texts | |
| return bank | |
| def get_episode_pool_path() -> Path: | |
| """Get the directory path for episode pool (relative to project root).""" | |
| # Find project root by looking for PLANS.md or README.md | |
| current = Path.cwd() | |
| while current != current.parent: | |
| if (current / "PLANS.md").exists() or (current / "README.md").exists(): | |
| path = current / EPISODES_DIR | |
| path.mkdir(parents=True, exist_ok=True) | |
| return path | |
| current = current.parent | |
| # Fallback to relative path | |
| path = Path(EPISODES_DIR) | |
| path.mkdir(parents=True, exist_ok=True) | |
| return path | |
| def get_all_episode_dirs() -> List[Path]: | |
| """Get all episode directories.""" | |
| pool_path = get_episode_pool_path() | |
| return sorted(pool_path.glob("ep_*")) | |