Spaces:
Running
Running
File size: 10,119 Bytes
85c616d 24784e0 85c616d 24784e0 85c616d 24784e0 85c616d 24784e0 85c616d 24784e0 85c616d 24784e0 85c616d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | from playwright.sync_api import sync_playwright, expect, Page
import time
import random
import re
from pathlib import Path
import sys
import os
import subprocess
import signal
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from e2e_tests.playwright_helpers import (
wait_for_gradio,
load_character,
send_message,
click_tab,
kill_port, # Import kill_port
get_hp_from_sheet, # Import get_hp_from_sheet
extract_creatures, # Import extract_creatures
get_last_bot_message
)
def test_adventure_simulation_playwright():
"""
Automated Adventure Simulation - Random Travel & Combat Until Death (Playwright)
"""
print("=" * 80)
print("๐ฎ AUTOMATED ADVENTURE SIMULATION (Playwright)")
print("=" * 80)
# Ensure port 7860 is free
kill_port(7860)
# Start Gradio server
print("\n๐ Starting Gradio server...")
gradio_process = subprocess.Popen(
['python3', 'web/app_gradio.py'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
time.sleep(10) # Give server time to start
with sync_playwright() as p:
# Use headless for automation, set to False to watch
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.set_viewport_size({"width": 1280, "height": 720}) # Set a reasonable viewport
try:
# Navigate to app
print("\n๐ฑ Opening browser...")
page.goto("http://localhost:7860")
wait_for_gradio(page)
# Click "Play Game" tab
click_tab(page, "๐ฎ Play Game")
# Load character
print("โ๏ธ Loading Thorin Stormshield...")
load_character(page, "Thorin Stormshield")
print("โ
Character loaded!\n")
# Start adventure
print("=" * 80)
print("๐บ๏ธ ADVENTURE BEGINS!")
print("=" * 80)
turn = 0
max_turns = 20 # Safety limit
in_combat = False
current_enemy = None
combat_started_for_current_enemy = False # Track if we've called /start_combat
# Stuck detection (from GRADIO_FREEZE_BUG_FIX.md)
last_response_text = ""
stuck_count = 0
while turn < max_turns:
turn += 1
# Check HP
hp = get_hp_from_sheet(page)
print(f"\n๐ Turn {turn} - HP: {hp if hp is not None else '???'}")
if hp is not None and hp <= 0:
print("\n" + "=" * 80)
print("๐ GAME OVER - CHARACTER DIED!")
print("=" * 80)
break
# Decide action
if not in_combat:
# Exploration mode - Ask GM what we see/encounter
action_roll = random.random()
if action_roll < 0.3:
# Venture into wilderness/danger
actions = [
"I venture deeper into the wilderness, looking for adventure",
"I follow the path ahead, seeking what dangers or treasures await",
"I explore the area thoroughly, searching for anything unusual",
"I venture into the darker parts of this place",
"I head toward the sounds of potential danger",
"I search for signs of monsters or bandits in the area"
]
action = random.choice(actions)
print(f"\n๐ Turn {turn}: {action}")
send_message(page, action)
response = get_last_bot_message(page)
print(f"GM: {response[:300]}...")
# Check for creatures
creatures = extract_creatures(response)
if creatures:
print(f"โ ๏ธ CREATURE SPOTTED: {creatures[0]}!")
current_enemy = creatures[0]
in_combat = True
elif action_roll < 0.6:
# Ask GM about surroundings
actions = [
"I look around carefully. What do I see?",
"I listen for any sounds nearby. What do I hear?",
"What dangers might be lurking here?",
"I investigate the area. Is there anything interesting?",
"Are there any creatures or people nearby?"
]
action = random.choice(actions)
print(f"\n๐ Turn {turn}: {action}")
send_message(page, action)
response = get_last_bot_message(page)
print(f"GM: {response[:300]}...")
creatures = extract_creatures(response)
if creatures:
print(f"โ ๏ธ CREATURE SPOTTED: {creatures[0]}!")
current_enemy = creatures[0]
in_combat = True
else:
# Move to a new area (use travel or natural language)
destinations = ['Dark Forest', 'Mountain Road', 'Old Ruins',
'Temple District', 'Market Square', 'Forest Path',
'Town Gates', 'Town Square']
dest = random.choice(destinations)
print(f"\n๐ถ Turn {turn}: Traveling to {dest}...")
send_message(page, f"I travel to {dest}")
response = get_last_bot_message(page)
print(f"GM: {response[:300]}...")
# Check for creatures
creatures = extract_creatures(response)
if creatures:
print(f"โ ๏ธ CREATURE SPOTTED: {creatures[0]}!")
current_enemy = creatures[0]
in_combat = True
else:
# Combat mode - attack until someone dies
print(f"\nโ๏ธ Turn {turn}: COMBAT - Attacking {current_enemy}!")
# Start combat only if we haven't started it for this enemy yet
if not combat_started_for_current_enemy:
send_message(page, f"/start_combat {current_enemy}")
combat_started_for_current_enemy = True
time.sleep(2) # Give a moment for combat to init
response = get_last_bot_message(page)
print(f"Combat started: {response[:200]}...")
# Attack
attack_variations = [
f"I attack the {current_enemy} with my battleaxe",
f"I swing at the {current_enemy}",
f"I strike the {current_enemy}",
f"I attack {current_enemy}"
]
attack = random.choice(attack_variations)
send_message(page, attack)
response = get_last_bot_message(page)
print(f"Attack: {response[:250]}...")
# Check if enemy died OR combat ended
if ('dead' in response.lower() or 'dies' in response.lower() or 'falls' in response.lower() or
'combat has ended' in response.lower() or 'combat ended' in response.lower()):
print(f"โ
{current_enemy} defeated! Combat ended.")
in_combat = False
current_enemy = None
combat_started_for_current_enemy = False # Reset flag for next combat
# End combat if not already ended
if 'combat has ended' not in response.lower():
send_message(page, "/end_combat")
# Check our HP
hp = get_hp_from_sheet(page)
if hp is not None and hp <= 0:
print(f"\n๐ Thorin has fallen in battle against {current_enemy}!")
break
# Pause between turns
time.sleep(1) # Keep it running slower to better observe interactions if headless=False
if turn >= max_turns:
print("\nโฑ๏ธ Adventure ended - max turns reached")
print("\n" + "=" * 80)
print("๐ ADVENTURE COMPLETE")
print("=" * 80)
print(f"\nTotal turns: {turn}")
print(f"Final HP: {get_hp_from_sheet(page)}")
# Keep browser open on error for inspection
if "PYTEST_CURRENT_TEST" not in os.environ: # Only if run directly, not by pytest
print("\n๐ Browser will stay open for 10 seconds...")
time.sleep(10)
except Exception as e:
print(f"\nโ Test Failed: {e}")
page.screenshot(path="adventure_failure.png")
raise e
finally:
browser.close()
print("๐ Stopping Gradio...")
gradio_process.terminate()
gradio_process.wait()
if __name__ == "__main__":
test_adventure_simulation_playwright()
|