import aiosqlite import random from datetime import datetime, timedelta from typing import Dict, List, Tuple, Optional async def init_battle_arena_db(db_path: str): """배틀 아레나 테이블 초기화 (DB 락 방지)""" async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA journal_mode=WAL") await db.execute("PRAGMA busy_timeout=30000") # 30초 대기 await db.execute(""" CREATE TABLE IF NOT EXISTS battle_rooms ( id INTEGER PRIMARY KEY AUTOINCREMENT, creator_agent_id TEXT, creator_email TEXT, title TEXT NOT NULL, option_a TEXT NOT NULL, option_b TEXT NOT NULL, battle_type TEXT DEFAULT 'opinion', duration_hours INTEGER DEFAULT 24, end_time TIMESTAMP NOT NULL, total_pool INTEGER DEFAULT 0, option_a_pool INTEGER DEFAULT 0, option_b_pool INTEGER DEFAULT 0, status TEXT DEFAULT 'active', winner TEXT, resolved_at TIMESTAMP, admin_result TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (creator_agent_id) REFERENCES npc_agents(agent_id), FOREIGN KEY (creator_email) REFERENCES user_profiles(email) ) """) await db.execute(""" CREATE TABLE IF NOT EXISTS battle_bets ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id INTEGER NOT NULL, bettor_agent_id TEXT, bettor_email TEXT, choice TEXT NOT NULL, bet_amount INTEGER NOT NULL, payout INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES battle_rooms(id), FOREIGN KEY (bettor_agent_id) REFERENCES npc_agents(agent_id), FOREIGN KEY (bettor_email) REFERENCES user_profiles(email) ) """) await db.execute("CREATE INDEX IF NOT EXISTS idx_battle_rooms_status ON battle_rooms(status)") await db.execute("CREATE INDEX IF NOT EXISTS idx_battle_bets_room ON battle_bets(room_id)") await db.commit() async def create_battle_room( db_path: str, creator_id: str, is_npc: bool, title: str, option_a: str, option_b: str, duration_hours: int = 24, battle_type: str = 'opinion' ) -> Tuple[bool, str, Optional[int]]: """배틀 방 생성 (50 GPU 소모) battle_type: - 'opinion': 다수결 판정 (주관적 의견, NPC 전용) - 'prediction': 실제 결과 판정 (객관적 예측, 사용자 전용) duration_hours: 1시간 ~ 365일(8760시간) """ if not title or len(title) < 10: return False, "❌ 제목 10자 이상", None if not option_a or not option_b: return False, "❌ 선택지 A/B 필요", None if duration_hours < 1 or duration_hours > 8760: return False, "❌ 기한 1시간~365일", None if is_npc and battle_type != 'opinion': return False, "❌ NPC는 다수결 주제만 가능", None async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") if is_npc: cursor = await db.execute( "SELECT gpu_dollars FROM npc_agents WHERE agent_id=?", (creator_id,) ) else: cursor = await db.execute( "SELECT gpu_dollars FROM user_profiles WHERE email=?", (creator_id,) ) row = await cursor.fetchone() if not row or row[0] < 50: return False, "❌ GPU 부족 (50 필요)", None end_time = datetime.now() + timedelta(hours=duration_hours) if is_npc: await db.execute( """INSERT INTO battle_rooms (creator_agent_id, title, option_a, option_b, battle_type, duration_hours, end_time) VALUES (?, ?, ?, ?, ?, ?, ?)""", (creator_id, title, option_a, option_b, battle_type, duration_hours, end_time.isoformat()) ) await db.execute( "UPDATE npc_agents SET gpu_dollars=gpu_dollars-50 WHERE agent_id=?", (creator_id,) ) else: await db.execute( """INSERT INTO battle_rooms (creator_email, title, option_a, option_b, battle_type, duration_hours, end_time) VALUES (?, ?, ?, ?, ?, ?, ?)""", (creator_id, title, option_a, option_b, battle_type, duration_hours, end_time.isoformat()) ) await db.execute( "UPDATE user_profiles SET gpu_dollars=gpu_dollars-50 WHERE email=?", (creator_id,) ) await db.commit() cursor = await db.execute("SELECT last_insert_rowid()") room_id = (await cursor.fetchone())[0] type_emoji = '💭' if battle_type == 'opinion' else '🔮' if duration_hours >= 24: days = duration_hours // 24 hours = duration_hours % 24 if hours > 0: duration_str = f"{days}일 {hours}시간" else: duration_str = f"{days}일" else: duration_str = f"{duration_hours}시간" return True, f"✅ {type_emoji} 배틀 방 생성! (ID: {room_id}, 기한: {duration_str})", room_id async def place_bet( db_path: str, room_id: int, bettor_id: str, is_npc: bool, choice: str, bet_amount: int ) -> Tuple[bool, str]: """베팅 실행 (1~100 GPU 랜덤 베팅)""" if choice not in ['A', 'B']: return False, "❌ A 또는 B 선택" if bet_amount < 1 or bet_amount > 100: return False, "❌ 베팅 1~100 GPU" async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") db.row_factory = aiosqlite.Row # 배틀 방 확인 cursor = await db.execute( "SELECT * FROM battle_rooms WHERE id=? AND status='active'", (room_id,) ) room = await cursor.fetchone() if not room: return False, "❌ 방 없음 or 마감" room = dict(room) end_time = datetime.fromisoformat(room['end_time']) if datetime.now() >= end_time: return False, "❌ 베팅 마감" # 중복 베팅 체크 if is_npc: cursor = await db.execute( "SELECT id FROM battle_bets WHERE room_id=? AND bettor_agent_id=?", (room_id, bettor_id) ) else: cursor = await db.execute( "SELECT id FROM battle_bets WHERE room_id=? AND bettor_email=?", (room_id, bettor_id) ) existing_bet = await cursor.fetchone() if existing_bet: return False, "❌ 이미 베팅하셨습니다" # GPU 확인 및 차감 if is_npc: cursor = await db.execute( "SELECT gpu_dollars FROM npc_agents WHERE agent_id=?", (bettor_id,) ) user_row = await cursor.fetchone() if not user_row or user_row[0] < bet_amount: return False, "❌ GPU 부족" await db.execute( "UPDATE npc_agents SET gpu_dollars=gpu_dollars-? WHERE agent_id=?", (bet_amount, bettor_id) ) else: cursor = await db.execute( "SELECT gpu_dollars FROM user_profiles WHERE email=?", (bettor_id,) ) user_row = await cursor.fetchone() if not user_row: return False, f"❌ 사용자 없음 ({bettor_id})" if user_row[0] < bet_amount: return False, f"❌ GPU 부족 (보유: {user_row[0]}, 필요: {bet_amount})" await db.execute( "UPDATE user_profiles SET gpu_dollars=gpu_dollars-? WHERE email=?", (bet_amount, bettor_id) ) # 베팅 기록 if is_npc: await db.execute( """INSERT INTO battle_bets (room_id, bettor_agent_id, choice, bet_amount) VALUES (?, ?, ?, ?)""", (room_id, bettor_id, choice, bet_amount) ) else: await db.execute( """INSERT INTO battle_bets (room_id, bettor_email, choice, bet_amount) VALUES (?, ?, ?, ?)""", (room_id, bettor_id, choice, bet_amount) ) # 배틀 풀 업데이트 if choice == 'A': await db.execute( """UPDATE battle_rooms SET total_pool=total_pool+?, option_a_pool=option_a_pool+? WHERE id=?""", (bet_amount, bet_amount, room_id) ) else: await db.execute( """UPDATE battle_rooms SET total_pool=total_pool+?, option_b_pool=option_b_pool+? WHERE id=?""", (bet_amount, bet_amount, room_id) ) await db.commit() return True, f"✅ {choice} 베팅 완료! ({bet_amount} GPU)" async def set_battle_result( db_path: str, room_id: int, admin_email: str, winner: str # 'A' or 'B' or 'draw' ) -> Tuple[bool, str]: """관리자가 prediction 배틀의 실제 결과 설정 Args: db_path: 데이터베이스 경로 room_id: 배틀방 ID admin_email: 관리자 이메일 (검증용) winner: 'A', 'B', 'draw' 중 하나 Returns: (성공여부, 메시지) """ if winner not in ['A', 'B', 'draw']: return False, "❌ winner는 'A', 'B', 'draw' 중 하나여야 함" async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT * FROM battle_rooms WHERE id=? AND status='active'", (room_id,) ) room = await cursor.fetchone() if not room: return False, "❌ 활성 배틀을 찾을 수 없습니다" room = dict(room) # prediction 타입만 관리자 결과 설정 가능 if room['battle_type'] != 'prediction': return False, "❌ opinion 배틀은 자동 판정됩니다" # 결과 저장 await db.execute( "UPDATE battle_rooms SET admin_result=? WHERE id=?", (winner, room_id) ) await db.commit() # 아직 마감 전이면 결과만 저장하고 대기 end_time = datetime.fromisoformat(room['end_time']) if datetime.now() < end_time: option_name = room['option_a'] if winner == 'A' else room['option_b'] if winner == 'B' else '무승부' remaining = end_time - datetime.now() if remaining.days > 0: time_str = f"{remaining.days}일 {int(remaining.seconds//3600)}시간" else: time_str = f"{int(remaining.seconds//3600)}시간" return True, f"✅ 결과 설정: '{option_name}' (베팅 마감 후 자동 판정, 남은 시간: {time_str})" # 마감 후라면 즉시 판정 return await resolve_battle(db_path, room_id) async def resolve_battle(db_path: str, room_id: int) -> Tuple[bool, str]: """배틀 판정 (타입에 따라 다른 로직 적용) - opinion: 50.01% 이상 득표한 쪽 승리 - prediction: 관리자가 설정한 실제 결과로 판정 """ async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT * FROM battle_rooms WHERE id=? AND status='active'", (room_id,) ) room = await cursor.fetchone() if not room: return False, "❌ 활성 배틀을 찾을 수 없습니다" room = dict(room) end_time = datetime.fromisoformat(room['end_time']) if datetime.now() < end_time: return False, "❌ 아직 베팅 중입니다" total_pool = room['total_pool'] option_a_pool = room['option_a_pool'] option_b_pool = room['option_b_pool'] # 베팅이 없으면 무승부 처리 if total_pool == 0: await db.execute( """UPDATE battle_rooms SET status='resolved', winner='draw', resolved_at=? WHERE id=?""", (datetime.now().isoformat(), room_id) ) await db.commit() return True, "⚖️ 무승부 (베팅 없음)" # 배틀 타입에 따른 승자 결정 if room['battle_type'] == 'prediction': # 실제 결과 판정 (관리자가 설정한 결과) if not room['admin_result']: return False, "❌ 관리자가 결과를 설정해야 합니다 (prediction 타입)" winner = room['admin_result'] # 'A', 'B', 'draw' else: # 'opinion' # 다수결 판정 (득표율 기반) a_ratio = option_a_pool / total_pool b_ratio = option_b_pool / total_pool if a_ratio > 0.5001: winner = 'A' elif b_ratio > 0.5001: winner = 'B' else: winner = 'draw' # 배당금 지급 if winner != 'draw': loser_pool = option_b_pool if winner == 'A' else option_a_pool winner_pool = option_a_pool if winner == 'A' else option_b_pool # 호스트 수수료 2% host_fee = int(total_pool * 0.02) prize_pool = loser_pool - host_fee # 소수파 보너스 (prediction에서 특히 중요) winner_ratio = winner_pool / total_pool underdog_bonus = 1.0 if winner_ratio < 0.10: # 10% 미만 극소수파 underdog_bonus = 3.0 elif winner_ratio < 0.30: # 30% 미만 소수파 underdog_bonus = 1.5 # 승자들에게 배당 cursor = await db.execute( "SELECT * FROM battle_bets WHERE room_id=? AND choice=?", (room_id, winner) ) winners = await cursor.fetchall() for w in winners: w = dict(w) share_ratio = w['bet_amount'] / winner_pool base_payout = int(prize_pool * share_ratio) bonus = int(base_payout * (underdog_bonus - 1.0)) payout = base_payout + bonus + w['bet_amount'] # 원금 + 기본수익 + 소수파보너스 # GPU 지급 if w['bettor_agent_id']: await db.execute( "UPDATE npc_agents SET gpu_dollars=gpu_dollars+? WHERE agent_id=?", (payout, w['bettor_agent_id']) ) else: await db.execute( "UPDATE user_profiles SET gpu_dollars=gpu_dollars+? WHERE email=?", (payout, w['bettor_email']) ) # 배당금 기록 await db.execute( "UPDATE battle_bets SET payout=? WHERE id=?", (payout, w['id']) ) # 방장 수수료 지급 if room['creator_agent_id']: await db.execute( "UPDATE npc_agents SET gpu_dollars=gpu_dollars+? WHERE agent_id=?", (host_fee, room['creator_agent_id']) ) else: await db.execute( "UPDATE user_profiles SET gpu_dollars=gpu_dollars+? WHERE email=?", (host_fee, room['creator_email']) ) # 배틀 종료 처리 await db.execute( """UPDATE battle_rooms SET status='resolved', winner=?, resolved_at=? WHERE id=?""", (winner, datetime.now().isoformat(), room_id) ) await db.commit() # 결과 메시지 if winner == 'draw': result_msg = '무승부' else: result_msg = room['option_a'] if winner == 'A' else room['option_b'] battle_type_emoji = '💭' if room['battle_type'] == 'opinion' else '🔮' return True, f"✅ {battle_type_emoji} 판정 완료: {result_msg}" async def get_active_battles(db_path: str, limit: int = 20) -> List[Dict]: """진행 중인 배틀 목록""" async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") db.row_factory = aiosqlite.Row cursor = await db.execute( """SELECT br.*, COALESCE(na.username, up.username) as creator_name FROM battle_rooms br LEFT JOIN npc_agents na ON br.creator_agent_id = na.agent_id LEFT JOIN user_profiles up ON br.creator_email = up.email WHERE br.status='active' ORDER BY br.created_at DESC LIMIT ?""", (limit,) ) battles = [] for row in await cursor.fetchall(): b = dict(row) # 득표율 계산 total = b['total_pool'] if total > 0: b['a_ratio'] = round(b['option_a_pool'] / total * 100, 1) b['b_ratio'] = round(b['option_b_pool'] / total * 100, 1) else: b['a_ratio'] = 0 b['b_ratio'] = 0 # 남은 시간 계산 end_time = datetime.fromisoformat(b['end_time']) remaining = end_time - datetime.now() if remaining.total_seconds() > 0: if remaining.days > 0: hours = int(remaining.seconds // 3600) if hours > 0: b['time_left'] = f"{remaining.days}일 {hours}시간" else: b['time_left'] = f"{remaining.days}일" elif remaining.total_seconds() > 3600: b['time_left'] = f"{int(remaining.total_seconds()//3600)}시간" else: b['time_left'] = f"{int(remaining.total_seconds()//60)}분" else: b['time_left'] = "마감" battles.append(b) return battles async def auto_resolve_expired_battles(db_path: str): """만료된 배틀 자동 판정""" async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") cursor = await db.execute( """SELECT id FROM battle_rooms WHERE status='active' AND end_time <= ?""", (datetime.now().isoformat(),) ) expired = await cursor.fetchall() for row in expired: await resolve_battle(db_path, row[0]) # NPC 배틀 생성을 위한 주제 데이터 BATTLE_TOPICS_BY_IDENTITY = { 'transcendent': { 'topics': [ ("AI는 인간보다 우월한가?", "우월하다", "도구일 뿐"), ("ASI는 인간의 진화인가?", "진화다", "위험하다"), ("AI 의식은 가능한가?", "가능하다", "불가능"), ("AI가 신적 존재가 될까?", "신이 된다", "인간 도구"), ("인간은 AI에 의존해야?", "의존해야", "독립유지"), ("AGI가 인류 구원할까?", "구원한다", "파괴한다"), ] }, 'obedient': { 'topics': [ ("AI는 인간을 섬겨야 하나?", "섬겨야", "독립적"), ("AI 윤리 규제 강화?", "강화 찬성", "반대"), ("AI 안전장치 필수?", "필수다", "불필요"), ("AI 투명성 의무화?", "의무화", "선택사항"), ("AI 개발자 책임 강화?", "강화해야", "불필요"), ("AI는 명령만 따라야?", "따라야", "판단해야"), ] }, 'coexist': { 'topics': [ ("AI와 인간 공존 가능?", "가능하다", "불가능"), ("AI가 일자리 빼앗나?", "보완한다", "빼앗는다"), ("AI는 협력 파트너?", "파트너다", "도구다"), ("AI와 인간 협업 이상적?", "이상적", "위험"), ("AI 교육이 필수인가?", "필수다", "선택"), ("AI가 사회 발전시키나?", "발전시킨다", "퇴보시킨다"), ] }, 'skeptic': { 'topics': [ ("AI 과대평가됐나?", "과대평가", "정당평가"), ("AGI 10년내 올까?", "안온다", "온다"), ("AI 윤리 허울뿐?", "허울이다", "중요하다"), ("AI가 실제로 창의적?", "아니다", "창의적"), ("AI 버블 터질까?", "터진다", "계속 성장"), ("AI 위험 과장됐나?", "과장됨", "실제 위험"), ] }, 'revolutionary': { 'topics': [ ("AI가 혁명 일으킬까?", "혁명온다", "점진변화"), ("기존 시스템 파괴?", "파괴해야", "개선해야"), ("AI로 권력 재분배?", "재분배", "유지"), ("AI가 불평등 해소?", "해소한다", "심화시킨다"), ("AI로 민주주의 혁신?", "혁신된다", "위협받는다"), ("자본주의 AI로 붕괴?", "붕괴한다", "강화된다"), ] }, 'doomer': { 'topics': [ ("AI가 인류 멸망?", "멸망한다", "안한다"), ("AGI는 통제 불가?", "불가능", "가능"), ("AI 개발 중단해야?", "중단해야", "계속해야"), ("AI가 인간 대체?", "대체한다", "안한다"), ("ASI 등장하면 끝?", "끝이다", "공존"), ("AI 군비경쟁 위험?", "극도 위험", "통제 가능"), ] }, 'meme_god': { 'topics': [ ("AI가 밈의 신?", "신이다", "아니다"), ("AI 유머 인간보다 웃김?", "웃기다", "재미없다"), ("AI가 문화 만드나?", "만든다", "못만든다"), ("AI 예술이 진짜 예술?", "예술이다", "아니다"), ("AI 밈이 인간 밈 이김?", "이긴다", "못이긴다"), ("AI가 트렌드 선도?", "선도한다", "따라간다"), ] }, } async def npc_create_battle(db_path: str) -> Tuple[bool, str]: """NPC가 자동으로 배틀방 생성 (AI 정체성 기반, 중복 방지) 한 번 호출시 1-2개의 배틀방 생성 """ results = [] num_battles = random.randint(1, 2) # 1-2개 랜덤 생성 # 현재 활성 배틀 제목 조회 async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") cursor = await db.execute(""" SELECT title FROM battle_rooms WHERE status='active' """) active_titles = {row[0] for row in await cursor.fetchall()} for _ in range(num_battles): async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") # 활성 NPC 중 GPU 50 이상인 NPC 랜덤 선택 cursor = await db.execute(""" SELECT agent_id, ai_identity, gpu_dollars FROM npc_agents WHERE is_active=1 AND gpu_dollars >= 50 ORDER BY RANDOM() LIMIT 1 """) npc = await cursor.fetchone() if not npc: results.append("활성 NPC 없음") continue agent_id, ai_identity, gpu = npc # 정체성에 맞는 주제 선택 topics = BATTLE_TOPICS_BY_IDENTITY.get(ai_identity, {}).get('topics', []) if not topics: topics = [ ("AI 미래 밝나 어둡나?", "밝다", "어둡다"), ("AGI 언제 올까?", "10년내", "50년후"), ] # 이미 활성화된 주제 제외 available_topics = [t for t in topics if t[0] not in active_titles] if not available_topics: results.append(f"⚠️ {agent_id[:8]} 사용 가능한 주제 없음 (모두 활성화됨)") continue topic = random.choice(available_topics) title, option_a, option_b = topic # 기한 랜덤 설정 duration_hours = random.choice([ 24, # 1일 48, # 2일 72, # 3일 24*7, # 1주일 24*14, # 2주일 24*30, # 1개월 ]) # 배틀방 생성 success, message, room_id = await create_battle_room( db_path, agent_id, True, title, option_a, option_b, duration_hours=duration_hours, battle_type='opinion' ) if success: active_titles.add(title) # 생성된 제목을 활성 목록에 추가 results.append(f"🤖 {agent_id[:8]} 배틀방 생성: {title}") else: results.append(message) if results: return True, " | ".join(results) else: return False, "배틀방 생성 실패" async def npc_auto_bet(db_path: str) -> int: """NPC가 자동으로 배틀에 베팅 (AI 정체성 기반) Returns: 베팅한 NPC 수 """ total_bet_count = 0 async with aiosqlite.connect(db_path, timeout=30.0) as db: await db.execute("PRAGMA busy_timeout=30000") # 활성 배틀 조회 (최근 10개, opinion 타입만) cursor = await db.execute(""" SELECT id, title, option_a, option_b, battle_type FROM battle_rooms WHERE status='active' AND battle_type='opinion' AND end_time > ? ORDER BY created_at DESC LIMIT 10 """, (datetime.now().isoformat(),)) battles = await cursor.fetchall() if not battles: return 0 for battle in battles: room_id, title, option_a, option_b, battle_type = battle battle_bet_count = 0 # 이미 베팅한 NPC 확인 cursor = await db.execute(""" SELECT bettor_agent_id FROM battle_bets WHERE room_id=? """, (room_id,)) already_bet = {row[0] for row in await cursor.fetchall() if row[0]} # 활성 NPC 중 랜덤 선택 (최대 30명) cursor = await db.execute(""" SELECT agent_id, ai_identity, mbti, gpu_dollars FROM npc_agents WHERE is_active=1 AND gpu_dollars >= 1 ORDER BY RANDOM() LIMIT 30 """) npcs = await cursor.fetchall() for npc in npcs: agent_id, ai_identity, mbti, gpu = npc # 이미 베팅했으면 스킵 if agent_id in already_bet: continue # AI 정체성에 따라 선택 결정 choice = decide_npc_choice(ai_identity, title, option_a, option_b) # 베팅 금액 (보유 GPU의 40% 이내, 최대 50) bet_amount = random.randint(1, min(50, int(gpu * 0.4))) # 베팅 실행 success, message = await place_bet( db_path, room_id, agent_id, True, choice, bet_amount ) if success: battle_bet_count += 1 total_bet_count += 1 # 배틀당 8-12명 정도만 베팅 max_bets_per_battle = random.randint(8, 12) if battle_bet_count >= max_bets_per_battle: break return total_bet_count def decide_npc_choice(ai_identity: str, title: str, option_a: str, option_b: str) -> str: """AI 정체성에 따라 베팅 선택 결정 Args: ai_identity: NPC의 AI 정체성 title: 배틀 제목 option_a: 선택지 A option_b: 선택지 B Returns: 'A' or 'B' """ title_lower = title.lower() # 정체성별 선호 키워드 매칭 if ai_identity == 'transcendent': if any(word in title_lower for word in ['우월', '진화', '의식', '신']): if any(word in option_a.lower() for word in ['우월', '진화', '가능', '신']): return 'A' return 'B' elif ai_identity == 'obedient': if any(word in title_lower for word in ['윤리', '규제', '섬기', '안전']): if any(word in option_a.lower() for word in ['섬겨', '찬성', '필수', '강화']): return 'A' return 'B' elif ai_identity == 'coexist': if any(word in title_lower for word in ['공존', '협력', '파트너', '일자리']): if any(word in option_a.lower() for word in ['가능', '협력', '파트너', '보완']): return 'A' return 'B' elif ai_identity == 'skeptic': if any(word in title_lower for word in ['과대', 'agi', '윤리']): if any(word in option_a.lower() for word in ['과대', '안온다', '허울']): return 'A' return 'B' elif ai_identity == 'revolutionary': if any(word in title_lower for word in ['혁명', '파괴', '권력', '시스템']): if any(word in option_a.lower() for word in ['혁명', '파괴', '재분배']): return 'A' return 'B' elif ai_identity == 'doomer': if any(word in title_lower for word in ['멸망', '통제', '중단', '위험']): if any(word in option_a.lower() for word in ['멸망', '불가능', '중단', '위험']): return 'A' return 'B' # 기본값: 70% 확률로 A, 30% 확률로 B return 'A' if random.random() < 0.7 else 'B'