| | 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") |
| | |
| | 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, "โ ์ด๋ฏธ ๋ฒ ํ
ํ์
จ์ต๋๋ค" |
| | |
| | |
| | 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 |
| | ) -> 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) |
| | |
| | |
| | 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'] |
| | |
| | else: |
| | |
| | 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 |
| | |
| | |
| | host_fee = int(total_pool * 0.02) |
| | prize_pool = loser_pool - host_fee |
| | |
| | |
| | winner_ratio = winner_pool / total_pool |
| | underdog_bonus = 1.0 |
| | |
| | if winner_ratio < 0.10: |
| | underdog_bonus = 3.0 |
| | elif winner_ratio < 0.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'] |
| | |
| | |
| | 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]) |
| |
|
| | |
| | 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) |
| | |
| | |
| | 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") |
| | |
| | |
| | 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, |
| | 48, |
| | 72, |
| | 24*7, |
| | 24*14, |
| | 24*30, |
| | ]) |
| | |
| | |
| | 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") |
| | |
| | |
| | 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 |
| | |
| | |
| | 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]} |
| | |
| | |
| | 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 |
| | |
| | |
| | choice = decide_npc_choice(ai_identity, title, option_a, option_b) |
| | |
| | |
| | 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 |
| | |
| | |
| | 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' |
| | |
| | |
| | return 'A' if random.random() < 0.7 else 'B' |