hack in a message broadcast system
This commit is contained in:
parent
ebf4ccf1c4
commit
8706badec5
|
@ -3,7 +3,7 @@ from logging import getLogger
|
||||||
|
|
||||||
from packit.utils import could_be_json
|
from packit.utils import could_be_json
|
||||||
|
|
||||||
from adventure.context import get_actor_agent_for_name, get_current_context
|
from adventure.context import broadcast, get_actor_agent_for_name, get_current_context
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
@ -16,29 +16,29 @@ def action_look(target: str) -> str:
|
||||||
target: The name of the target to look at.
|
target: The name of the target to look at.
|
||||||
"""
|
"""
|
||||||
_, action_room, action_actor = get_current_context()
|
_, action_room, action_actor = get_current_context()
|
||||||
logger.info(f"{action_actor.name} looks at {target}")
|
broadcast(f"{action_actor.name} looks at {target}")
|
||||||
|
|
||||||
if target == action_room.name:
|
if target == action_room.name:
|
||||||
logger.info(f"{action_actor.name} saw the {action_room.name} room")
|
broadcast(f"{action_actor.name} saw the {action_room.name} room")
|
||||||
return action_room.description
|
return action_room.description
|
||||||
|
|
||||||
for actor in action_room.actors:
|
for actor in action_room.actors:
|
||||||
if actor.name == target:
|
if actor.name == target:
|
||||||
logger.info(
|
broadcast(
|
||||||
f"{action_actor.name} saw the {actor.name} actor in the {action_room.name} room"
|
f"{action_actor.name} saw the {actor.name} actor in the {action_room.name} room"
|
||||||
)
|
)
|
||||||
return actor.description
|
return actor.description
|
||||||
|
|
||||||
for item in action_room.items:
|
for item in action_room.items:
|
||||||
if item.name == target:
|
if item.name == target:
|
||||||
logger.info(
|
broadcast(
|
||||||
f"{action_actor.name} saw the {item.name} item in the {action_room.name} room"
|
f"{action_actor.name} saw the {item.name} item in the {action_room.name} room"
|
||||||
)
|
)
|
||||||
return item.description
|
return item.description
|
||||||
|
|
||||||
for item in action_actor.items:
|
for item in action_actor.items:
|
||||||
if item.name == target:
|
if item.name == target:
|
||||||
logger.info(
|
broadcast(
|
||||||
f"{action_actor.name} saw the {item.name} item in their inventory"
|
f"{action_actor.name} saw the {item.name} item in their inventory"
|
||||||
)
|
)
|
||||||
return item.description
|
return item.description
|
||||||
|
@ -65,7 +65,7 @@ def action_move(direction: str) -> str:
|
||||||
if not destination_room:
|
if not destination_room:
|
||||||
return f"The {destination_name} room does not exist."
|
return f"The {destination_name} room does not exist."
|
||||||
|
|
||||||
logger.info(f"{action_actor.name} moves {direction} to {destination_name}")
|
broadcast(f"{action_actor.name} moves {direction} to {destination_name}")
|
||||||
action_room.actors.remove(action_actor)
|
action_room.actors.remove(action_actor)
|
||||||
destination_room.actors.append(action_actor)
|
destination_room.actors.append(action_actor)
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ def action_take(item_name: str) -> str:
|
||||||
|
|
||||||
item = next((item for item in action_room.items if item.name == item_name), None)
|
item = next((item for item in action_room.items if item.name == item_name), None)
|
||||||
if item:
|
if item:
|
||||||
logger.info(f"{action_actor.name} takes the {item_name} item")
|
broadcast(f"{action_actor.name} takes the {item_name} item")
|
||||||
action_room.items.remove(item)
|
action_room.items.remove(item)
|
||||||
action_actor.items.append(item)
|
action_actor.items.append(item)
|
||||||
return "You take the {item_name} item and put it in your inventory."
|
return "You take the {item_name} item and put it in your inventory."
|
||||||
|
@ -118,7 +118,7 @@ def action_ask(character: str, question: str) -> str:
|
||||||
if not question_agent:
|
if not question_agent:
|
||||||
return f"The {character} character does not exist."
|
return f"The {character} character does not exist."
|
||||||
|
|
||||||
logger.info(f"{action_actor.name} asks {character}: {question}")
|
broadcast(f"{action_actor.name} asks {character}: {question}")
|
||||||
answer = question_agent(
|
answer = question_agent(
|
||||||
f"{action_actor.name} asks you: {question}. Reply with your response to them. "
|
f"{action_actor.name} asks you: {question}. Reply with your response to them. "
|
||||||
f"Do not include the question or any JSON. Only include your answer for {action_actor.name}."
|
f"Do not include the question or any JSON. Only include your answer for {action_actor.name}."
|
||||||
|
@ -128,7 +128,7 @@ def action_ask(character: str, question: str) -> str:
|
||||||
answer = loads(answer).get("parameters", {}).get("message", "")
|
answer = loads(answer).get("parameters", {}).get("message", "")
|
||||||
|
|
||||||
if len(answer.strip()) > 0:
|
if len(answer.strip()) > 0:
|
||||||
logger.info(f"{character} responds to {action_actor.name}: {answer}")
|
broadcast(f"{character} responds to {action_actor.name}: {answer}")
|
||||||
return f"{character} responds: {answer}"
|
return f"{character} responds: {answer}"
|
||||||
|
|
||||||
return f"{character} does not respond."
|
return f"{character} does not respond."
|
||||||
|
@ -161,7 +161,7 @@ def action_tell(character: str, message: str) -> str:
|
||||||
if not question_agent:
|
if not question_agent:
|
||||||
return f"The {character} character does not exist."
|
return f"The {character} character does not exist."
|
||||||
|
|
||||||
logger.info(f"{action_actor.name} tells {character}: {message}")
|
broadcast(f"{action_actor.name} tells {character}: {message}")
|
||||||
answer = question_agent(
|
answer = question_agent(
|
||||||
f"{action_actor.name} tells you: {message}. Reply with your response to them. "
|
f"{action_actor.name} tells you: {message}. Reply with your response to them. "
|
||||||
f"Do not include the message or any JSON. Only include your reply to {action_actor.name}."
|
f"Do not include the message or any JSON. Only include your reply to {action_actor.name}."
|
||||||
|
@ -171,7 +171,7 @@ def action_tell(character: str, message: str) -> str:
|
||||||
answer = loads(answer).get("parameters", {}).get("message", "")
|
answer = loads(answer).get("parameters", {}).get("message", "")
|
||||||
|
|
||||||
if len(answer.strip()) > 0:
|
if len(answer.strip()) > 0:
|
||||||
logger.info(f"{character} responds to {action_actor.name}: {answer}")
|
broadcast(f"{character} responds to {action_actor.name}: {answer}")
|
||||||
return f"{character} responds: {answer}"
|
return f"{character} responds: {answer}"
|
||||||
|
|
||||||
return f"{character} does not respond."
|
return f"{character} does not respond."
|
||||||
|
@ -197,7 +197,7 @@ def action_give(character: str, item_name: str) -> str:
|
||||||
if not item:
|
if not item:
|
||||||
return f"You do not have the {item_name} item in your inventory."
|
return f"You do not have the {item_name} item in your inventory."
|
||||||
|
|
||||||
logger.info(f"{action_actor.name} gives {character} the {item_name} item")
|
broadcast(f"{action_actor.name} gives {character} the {item_name} item")
|
||||||
action_actor.items.remove(item)
|
action_actor.items.remove(item)
|
||||||
destination_actor.items.append(item)
|
destination_actor.items.append(item)
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ def action_drop(item_name: str) -> str:
|
||||||
if not item:
|
if not item:
|
||||||
return f"You do not have the {item_name} item in your inventory."
|
return f"You do not have the {item_name} item in your inventory."
|
||||||
|
|
||||||
logger.info(f"{action_actor.name} drops the {item_name} item")
|
broadcast(f"{action_actor.name} drops the {item_name} item")
|
||||||
action_actor.items.remove(item)
|
action_actor.items.remove(item)
|
||||||
action_room.items.append(item)
|
action_room.items.append(item)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from typing import Dict, Tuple
|
from typing import Callable, Dict, Tuple
|
||||||
|
|
||||||
from packit.agent import Agent
|
from packit.agent import Agent
|
||||||
|
|
||||||
from adventure.models import Actor
|
from adventure.models import Actor, Room, World
|
||||||
|
|
||||||
current_world = None
|
current_broadcast: Callable[[str], None] | None = None
|
||||||
current_room = None
|
current_world: World | None = None
|
||||||
current_actor = None
|
current_room: Room | None = None
|
||||||
|
current_actor: Actor | None = None
|
||||||
current_step = 0
|
current_step = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,6 +42,20 @@ def get_current_actor():
|
||||||
return current_actor
|
return current_actor
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_broadcast():
|
||||||
|
return current_broadcast
|
||||||
|
|
||||||
|
|
||||||
|
def broadcast(message):
|
||||||
|
if current_broadcast:
|
||||||
|
current_broadcast(message)
|
||||||
|
|
||||||
|
|
||||||
|
def set_current_broadcast(broadcast):
|
||||||
|
global current_broadcast
|
||||||
|
current_broadcast = broadcast
|
||||||
|
|
||||||
|
|
||||||
def set_current_world(world):
|
def set_current_world(world):
|
||||||
global current_world
|
global current_world
|
||||||
current_world = world
|
current_world = world
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from random import choice, randint
|
from random import choice, randint
|
||||||
from typing import List
|
from typing import Callable, List
|
||||||
|
|
||||||
from packit.agent import Agent
|
from packit.agent import Agent
|
||||||
|
|
||||||
|
@ -9,7 +9,9 @@ from adventure.models import Actor, Item, Room, World
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def generate_room(agent: Agent, world_theme: str, existing_rooms: List[str]) -> Room:
|
def generate_room(
|
||||||
|
agent: Agent, world_theme: str, existing_rooms: List[str], callback
|
||||||
|
) -> Room:
|
||||||
name = agent(
|
name = agent(
|
||||||
"Generate one room, area, or location that would make sense in the world of {world_theme}. "
|
"Generate one room, area, or location that would make sense in the world of {world_theme}. "
|
||||||
"Only respond with the room name, do not include the description or any other text. "
|
"Only respond with the room name, do not include the description or any other text. "
|
||||||
|
@ -17,7 +19,7 @@ def generate_room(agent: Agent, world_theme: str, existing_rooms: List[str]) ->
|
||||||
world_theme=world_theme,
|
world_theme=world_theme,
|
||||||
existing_rooms=existing_rooms,
|
existing_rooms=existing_rooms,
|
||||||
)
|
)
|
||||||
logger.info(f"Generating room: {name}")
|
callback(f"Generating room: {name}")
|
||||||
desc = agent(
|
desc = agent(
|
||||||
"Generate a detailed description of the {name} area. What does it look like? "
|
"Generate a detailed description of the {name} area. What does it look like? "
|
||||||
"What does it smell like? What can be seen or heard?",
|
"What does it smell like? What can be seen or heard?",
|
||||||
|
@ -36,9 +38,10 @@ def generate_room(agent: Agent, world_theme: str, existing_rooms: List[str]) ->
|
||||||
def generate_item(
|
def generate_item(
|
||||||
agent: Agent,
|
agent: Agent,
|
||||||
world_theme: str,
|
world_theme: str,
|
||||||
|
existing_items: List[str],
|
||||||
|
callback,
|
||||||
dest_room: str | None = None,
|
dest_room: str | None = None,
|
||||||
dest_actor: str | None = None,
|
dest_actor: str | None = None,
|
||||||
existing_items: List[str] = [],
|
|
||||||
) -> Item:
|
) -> Item:
|
||||||
if dest_actor:
|
if dest_actor:
|
||||||
dest_note = "The item will be held by the {dest_actor} character"
|
dest_note = "The item will be held by the {dest_actor} character"
|
||||||
|
@ -56,7 +59,7 @@ def generate_item(
|
||||||
existing_items=existing_items,
|
existing_items=existing_items,
|
||||||
world_theme=world_theme,
|
world_theme=world_theme,
|
||||||
)
|
)
|
||||||
logger.info(f"Generating item: {name}")
|
callback(f"Generating item: {name}")
|
||||||
desc = agent(
|
desc = agent(
|
||||||
"Generate a detailed description of the {name} item. What does it look like? What is it made of? What does it do?",
|
"Generate a detailed description of the {name} item. What does it look like? What is it made of? What does it do?",
|
||||||
name=name,
|
name=name,
|
||||||
|
@ -68,7 +71,7 @@ def generate_item(
|
||||||
|
|
||||||
|
|
||||||
def generate_actor(
|
def generate_actor(
|
||||||
agent: Agent, world_theme: str, dest_room: str, existing_actors: List[str] = []
|
agent: Agent, world_theme: str, dest_room: str, existing_actors: List[str], callback
|
||||||
) -> Actor:
|
) -> Actor:
|
||||||
name = agent(
|
name = agent(
|
||||||
"Generate one person or creature that would make sense in the world of {world_theme}. The character will be placed in the {dest_room} room. "
|
"Generate one person or creature that would make sense in the world of {world_theme}. The character will be placed in the {dest_room} room. "
|
||||||
|
@ -79,7 +82,7 @@ def generate_actor(
|
||||||
existing_actors=existing_actors,
|
existing_actors=existing_actors,
|
||||||
world_theme=world_theme,
|
world_theme=world_theme,
|
||||||
)
|
)
|
||||||
logger.info(f"Generating actor: {name}")
|
callback(f"Generating actor: {name}")
|
||||||
description = agent(
|
description = agent(
|
||||||
"Generate a detailed description of the {name} character. What do they look like? What are they wearing? "
|
"Generate a detailed description of the {name} character. What do they look like? What are they wearing? "
|
||||||
"What are they doing? Describe their appearance from the perspective of an outside observer."
|
"What are they doing? Describe their appearance from the perspective of an outside observer."
|
||||||
|
@ -106,9 +109,10 @@ def generate_world(
|
||||||
theme: str,
|
theme: str,
|
||||||
room_count: int | None = None,
|
room_count: int | None = None,
|
||||||
max_rooms: int = 5,
|
max_rooms: int = 5,
|
||||||
|
callback: Callable[[str], None] = lambda x: None,
|
||||||
) -> World:
|
) -> World:
|
||||||
room_count = room_count or randint(3, max_rooms)
|
room_count = room_count or randint(3, max_rooms)
|
||||||
logger.info(f"Generating a {theme} with {room_count} rooms")
|
callback(f"Generating a {theme} with {room_count} rooms")
|
||||||
|
|
||||||
existing_actors: List[str] = []
|
existing_actors: List[str] = []
|
||||||
existing_items: List[str] = []
|
existing_items: List[str] = []
|
||||||
|
@ -117,30 +121,48 @@ def generate_world(
|
||||||
rooms = []
|
rooms = []
|
||||||
for i in range(room_count):
|
for i in range(room_count):
|
||||||
existing_rooms = [room.name for room in rooms]
|
existing_rooms = [room.name for room in rooms]
|
||||||
room = generate_room(agent, theme, existing_rooms)
|
room = generate_room(agent, theme, existing_rooms, callback=callback)
|
||||||
rooms.append(room)
|
rooms.append(room)
|
||||||
|
|
||||||
item_count = randint(0, 3)
|
item_count = randint(0, 3)
|
||||||
|
callback(f"Generating {item_count} items for room {room.name}")
|
||||||
|
|
||||||
for j in range(item_count):
|
for j in range(item_count):
|
||||||
item = generate_item(
|
item = generate_item(
|
||||||
agent, theme, dest_room=room.name, existing_items=existing_items
|
agent,
|
||||||
|
theme,
|
||||||
|
dest_room=room.name,
|
||||||
|
existing_items=existing_items,
|
||||||
|
callback=callback,
|
||||||
)
|
)
|
||||||
room.items.append(item)
|
room.items.append(item)
|
||||||
existing_items.append(item.name)
|
existing_items.append(item.name)
|
||||||
|
|
||||||
actor_count = randint(0, 3)
|
actor_count = randint(0, 3)
|
||||||
|
callback(f"Generating {actor_count} actors for room {room.name}")
|
||||||
|
|
||||||
for j in range(actor_count):
|
for j in range(actor_count):
|
||||||
actor = generate_actor(
|
actor = generate_actor(
|
||||||
agent, theme, dest_room=room.name, existing_actors=existing_actors
|
agent,
|
||||||
|
theme,
|
||||||
|
dest_room=room.name,
|
||||||
|
existing_actors=existing_actors,
|
||||||
|
callback=callback,
|
||||||
)
|
)
|
||||||
room.actors.append(actor)
|
room.actors.append(actor)
|
||||||
existing_actors.append(actor.name)
|
existing_actors.append(actor.name)
|
||||||
|
|
||||||
# generate the actor's inventory
|
# generate the actor's inventory
|
||||||
item_count = randint(0, 3)
|
item_count = randint(0, 3)
|
||||||
|
callback(f"Generating {item_count} items for actor {actor.name}")
|
||||||
|
|
||||||
for k in range(item_count):
|
for k in range(item_count):
|
||||||
item = generate_item(
|
item = generate_item(
|
||||||
agent, theme, dest_room=room.name, existing_items=existing_items
|
agent,
|
||||||
|
theme,
|
||||||
|
dest_room=room.name,
|
||||||
|
existing_items=existing_items,
|
||||||
|
callback=callback,
|
||||||
)
|
)
|
||||||
actor.items.append(item)
|
actor.items.append(item)
|
||||||
existing_items.append(item.name)
|
existing_items.append(item.name)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from json import load
|
from json import load
|
||||||
|
from logging.config import dictConfig
|
||||||
from os import environ, path
|
from os import environ, path
|
||||||
from typing import Callable, Dict, Sequence, Tuple
|
from typing import Callable, Dict, Sequence, Tuple
|
||||||
|
|
||||||
|
@ -10,6 +11,23 @@ from packit.results import multi_function_or_str_result
|
||||||
from packit.toolbox import Toolbox
|
from packit.toolbox import Toolbox
|
||||||
from packit.utils import logger_with_colors
|
from packit.utils import logger_with_colors
|
||||||
|
|
||||||
|
from adventure.context import set_current_broadcast
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
LOG_PATH = "logging.json"
|
||||||
|
# LOG_PATH = "dev-logging.json"
|
||||||
|
try:
|
||||||
|
if path.exists(LOG_PATH):
|
||||||
|
with open(LOG_PATH, "r") as f:
|
||||||
|
config_logging = load(f)
|
||||||
|
dictConfig(config_logging)
|
||||||
|
else:
|
||||||
|
print("logging config not found")
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
print("error loading logging config: %s" % (err))
|
||||||
|
|
||||||
|
if True:
|
||||||
from adventure.actions import (
|
from adventure.actions import (
|
||||||
action_ask,
|
action_ask,
|
||||||
action_give,
|
action_give,
|
||||||
|
@ -32,7 +50,7 @@ from adventure.generate import generate_world
|
||||||
from adventure.models import Actor, Room, World, WorldState
|
from adventure.models import Actor, Room, World, WorldState
|
||||||
from adventure.state import create_agents, save_world, save_world_state
|
from adventure.state import create_agents, save_world, save_world_state
|
||||||
|
|
||||||
logger = logger_with_colors(__name__)
|
logger = logger_with_colors(__name__, level="INFO")
|
||||||
|
|
||||||
load_dotenv(environ.get("ADVENTURE_ENV", ".env"), override=True)
|
load_dotenv(environ.get("ADVENTURE_ENV", ".env"), override=True)
|
||||||
|
|
||||||
|
@ -65,12 +83,21 @@ def simulate_world(
|
||||||
systems: Sequence[
|
systems: Sequence[
|
||||||
Tuple[Callable[[World, int], None], Callable[[Dict[str, str]], str] | None]
|
Tuple[Callable[[World, int], None], Callable[[Dict[str, str]], str] | None]
|
||||||
] = [],
|
] = [],
|
||||||
|
event_callbacks: Sequence[Callable[[str], None]] = [],
|
||||||
input_callbacks: Sequence[Callable[[Room, Actor, str], None]] = [],
|
input_callbacks: Sequence[Callable[[Room, Actor, str], None]] = [],
|
||||||
result_callbacks: Sequence[Callable[[Room, Actor, str], None]] = [],
|
result_callbacks: Sequence[Callable[[Room, Actor, str], None]] = [],
|
||||||
):
|
):
|
||||||
logger.info("Simulating the world")
|
logger.info("Simulating the world")
|
||||||
set_current_world(world)
|
set_current_world(world)
|
||||||
|
|
||||||
|
# set up a broadcast callback
|
||||||
|
def broadcast_callback(message):
|
||||||
|
logger.info(message)
|
||||||
|
for callback in event_callbacks:
|
||||||
|
callback(message)
|
||||||
|
|
||||||
|
set_current_broadcast(broadcast_callback)
|
||||||
|
|
||||||
# build a toolbox for the actions
|
# build a toolbox for the actions
|
||||||
action_tools = Toolbox(
|
action_tools = Toolbox(
|
||||||
[
|
[
|
||||||
|
@ -222,6 +249,25 @@ def main():
|
||||||
if args.player:
|
if args.player:
|
||||||
players.append(args.player)
|
players.append(args.player)
|
||||||
|
|
||||||
|
# set up callbacks
|
||||||
|
event_callbacks = []
|
||||||
|
input_callbacks = []
|
||||||
|
result_callbacks = []
|
||||||
|
|
||||||
|
if args.server:
|
||||||
|
from adventure.server import (
|
||||||
|
launch_server,
|
||||||
|
server_action,
|
||||||
|
server_event,
|
||||||
|
server_result,
|
||||||
|
server_system,
|
||||||
|
)
|
||||||
|
|
||||||
|
launch_server()
|
||||||
|
event_callbacks.append(server_event)
|
||||||
|
input_callbacks.append(server_action)
|
||||||
|
result_callbacks.append(server_result)
|
||||||
|
|
||||||
memory = {}
|
memory = {}
|
||||||
if path.exists(world_state_file):
|
if path.exists(world_state_file):
|
||||||
logger.info(f"Loading world state from {world_state_file}")
|
logger.info(f"Loading world state from {world_state_file}")
|
||||||
|
@ -246,12 +292,23 @@ def main():
|
||||||
{},
|
{},
|
||||||
llm,
|
llm,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
world = None
|
||||||
|
|
||||||
|
def broadcast_callback(message):
|
||||||
|
logger.info(message)
|
||||||
|
for callback in event_callbacks:
|
||||||
|
callback(message)
|
||||||
|
if args.server and world:
|
||||||
|
server_system(world, 0)
|
||||||
|
|
||||||
world = generate_world(
|
world = generate_world(
|
||||||
agent,
|
agent,
|
||||||
args.world,
|
args.world,
|
||||||
args.theme,
|
args.theme,
|
||||||
room_count=args.rooms,
|
room_count=args.rooms,
|
||||||
max_rooms=args.max_rooms,
|
max_rooms=args.max_rooms,
|
||||||
|
callback=broadcast_callback,
|
||||||
)
|
)
|
||||||
save_world(world, world_file)
|
save_world(world, world_file)
|
||||||
|
|
||||||
|
@ -281,22 +338,9 @@ def main():
|
||||||
)
|
)
|
||||||
extra_systems.append(module_systems)
|
extra_systems.append(module_systems)
|
||||||
|
|
||||||
# make sure the server system is last
|
# make sure the server system runs after any updates
|
||||||
input_callbacks = []
|
|
||||||
result_callbacks = []
|
|
||||||
|
|
||||||
if args.server:
|
if args.server:
|
||||||
from adventure.server import (
|
|
||||||
launch_server,
|
|
||||||
server_input,
|
|
||||||
server_result,
|
|
||||||
server_system,
|
|
||||||
)
|
|
||||||
|
|
||||||
launch_server()
|
|
||||||
extra_systems.append((server_system, None))
|
extra_systems.append((server_system, None))
|
||||||
input_callbacks.append(server_input)
|
|
||||||
result_callbacks.append(server_result)
|
|
||||||
|
|
||||||
# start the sim
|
# start the sim
|
||||||
logger.debug("Simulating world: %s", world)
|
logger.debug("Simulating world: %s", world)
|
||||||
|
|
|
@ -1,60 +1,75 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from collections import deque
|
||||||
from json import dumps
|
from json import dumps
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
import websockets
|
import websockets
|
||||||
from flask import Flask, send_from_directory
|
|
||||||
|
|
||||||
from adventure.models import Actor, Room, World
|
from adventure.models import Actor, Room, World
|
||||||
from adventure.state import snapshot_world, world_json
|
from adventure.state import snapshot_world, world_json
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
connected = set()
|
connected = set()
|
||||||
|
recent_events = deque(maxlen=10)
|
||||||
|
recent_world = None
|
||||||
@app.route("/<path:page>")
|
|
||||||
def send_report(page: str):
|
|
||||||
print(f"Sending {page}")
|
|
||||||
return send_from_directory(
|
|
||||||
"/home/ssube/code/github/ssube/llm-adventure/web-ui", page
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def handler(websocket):
|
async def handler(websocket):
|
||||||
|
logger.info("Client connected")
|
||||||
connected.add(websocket)
|
connected.add(websocket)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if recent_world:
|
||||||
|
await websocket.send(recent_world)
|
||||||
|
|
||||||
|
for message in recent_events:
|
||||||
|
await websocket.send(message)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to send recent messages to new client")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# await websocket.wait_closed()
|
|
||||||
message = await websocket.recv()
|
message = await websocket.recv()
|
||||||
print(message)
|
print(message)
|
||||||
except websockets.ConnectionClosedOK:
|
except websockets.ConnectionClosedOK:
|
||||||
break
|
break
|
||||||
|
|
||||||
connected.remove(websocket)
|
connected.remove(websocket)
|
||||||
|
logger.info("Client disconnected")
|
||||||
|
|
||||||
|
|
||||||
socket_thread = None
|
socket_thread = None
|
||||||
static_thread = None
|
static_thread = None
|
||||||
|
|
||||||
|
|
||||||
|
def server_json(obj):
|
||||||
|
if isinstance(obj, Actor):
|
||||||
|
return obj.name
|
||||||
|
|
||||||
|
if isinstance(obj, Room):
|
||||||
|
return obj.name
|
||||||
|
|
||||||
|
return world_json(obj)
|
||||||
|
|
||||||
|
|
||||||
|
def send_and_append(message):
|
||||||
|
json_message = dumps(message, default=server_json)
|
||||||
|
recent_events.append(json_message)
|
||||||
|
websockets.broadcast(connected, json_message)
|
||||||
|
return json_message
|
||||||
|
|
||||||
|
|
||||||
def launch_server():
|
def launch_server():
|
||||||
global socket_thread, static_thread
|
global socket_thread, static_thread
|
||||||
|
|
||||||
def run_sockets():
|
def run_sockets():
|
||||||
asyncio.run(server_main())
|
asyncio.run(server_main())
|
||||||
|
|
||||||
def run_static():
|
|
||||||
app.run(port=8000)
|
|
||||||
|
|
||||||
socket_thread = Thread(target=run_sockets)
|
socket_thread = Thread(target=run_sockets)
|
||||||
socket_thread.start()
|
socket_thread.start()
|
||||||
|
|
||||||
static_thread = Thread(target=run_static)
|
|
||||||
static_thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
async def server_main():
|
async def server_main():
|
||||||
async with websockets.serve(handler, "", 8001):
|
async with websockets.serve(handler, "", 8001):
|
||||||
|
@ -63,28 +78,37 @@ async def server_main():
|
||||||
|
|
||||||
|
|
||||||
def server_system(world: World, step: int):
|
def server_system(world: World, step: int):
|
||||||
|
global recent_world
|
||||||
json_state = {
|
json_state = {
|
||||||
**snapshot_world(world, step),
|
**snapshot_world(world, step),
|
||||||
"type": "world",
|
"type": "world",
|
||||||
}
|
}
|
||||||
websockets.broadcast(connected, dumps(json_state, default=world_json))
|
recent_world = send_and_append(json_state)
|
||||||
|
|
||||||
|
|
||||||
def server_result(room: Room, actor: Actor, action: str):
|
def server_result(room: Room, actor: Actor, action: str):
|
||||||
json_action = {
|
json_action = {
|
||||||
"actor": actor.name,
|
"actor": actor,
|
||||||
"result": action,
|
"result": action,
|
||||||
"room": room.name,
|
"room": room,
|
||||||
"type": "result",
|
"type": "result",
|
||||||
}
|
}
|
||||||
websockets.broadcast(connected, dumps(json_action))
|
send_and_append(json_action)
|
||||||
|
|
||||||
|
|
||||||
def server_input(room: Room, actor: Actor, message: str):
|
def server_action(room: Room, actor: Actor, message: str):
|
||||||
json_input = {
|
json_input = {
|
||||||
"actor": actor.name,
|
"actor": actor,
|
||||||
"input": message,
|
"input": message,
|
||||||
"room": room.name,
|
"room": room,
|
||||||
"type": "input",
|
"type": "action",
|
||||||
}
|
}
|
||||||
websockets.broadcast(connected, dumps(json_input))
|
send_and_append(json_input)
|
||||||
|
|
||||||
|
|
||||||
|
def server_event(message: str):
|
||||||
|
json_broadcast = {
|
||||||
|
"message": message,
|
||||||
|
"type": "event",
|
||||||
|
}
|
||||||
|
send_and_append(json_broadcast)
|
||||||
|
|
Loading…
Reference in New Issue