feat: implement core D&D helpers logic and system architecture
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,61 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
from src.llm.models import ExtractionResult
|
||||
from src.llm.processor import LLMProcessor
|
||||
|
||||
# Sample transcripts for testing
|
||||
SAMPLE_TRANSCRIPTS = [
|
||||
"""
|
||||
Player 1: I think I'll move towards the door.
|
||||
Player 2: Wait, let me check my inventory. I have a torch, right?
|
||||
Player 1: Yeah, you have one torch.
|
||||
Player 2: Okay, I'm going to light it.
|
||||
DM: As you light the torch, you see a strange symbol on the wall. It's a red eye.
|
||||
Player 1: Oh, cool.
|
||||
Player 2: Wait, did I say that? I mean, I'm moving.
|
||||
Player 1: Let's just go.
|
||||
""",
|
||||
"""
|
||||
Player 1: I attack the goblin!
|
||||
DM: Roll for it.
|
||||
Player 1: I got a 15.
|
||||
DM: The goblin is hit. It takes 8 damage.
|
||||
Player 1: Nice.
|
||||
Player 2: I'll use a healing potion on Player 1.
|
||||
DM: Okay, Player 1 recovers 10 HP.
|
||||
Player 1: Thanks.
|
||||
Player 2: By the way, does anyone have a snack?
|
||||
Player 1: I think there's some in the kitchen.
|
||||
""",
|
||||
"""
|
||||
DM: You enter the City of Silverspire. Silverspire is known for its floating gardens.
|
||||
Player 1: Wow, floating gardens.
|
||||
Player 2: I want to talk to the guard.
|
||||
DM: The guard is an old dwarf named Thorne. Thorne is the Captain of the Guard.
|
||||
Player 1: Thorne seems grumpy.
|
||||
Player 2: Let's ask him about the floating gardens.
|
||||
""",
|
||||
]
|
||||
|
||||
|
||||
def test_llm_pipeline():
|
||||
# Mocking the API key for the test.
|
||||
# In a real scenario, this should be in .env
|
||||
os.environ["OPENAI_API_KEY"] = "sk-test-key"
|
||||
|
||||
# We need a Mock LLM Processor for the unit test since we don't have a live API key.
|
||||
# However, the task asks for a verification report.
|
||||
# I will implement a mock and a real test function.
|
||||
|
||||
processor = LLMProcessor()
|
||||
|
||||
for i, transcript in enumerate(SAMPLE_TRANSCRIPTS):
|
||||
print(f"--- Testing Transcript {i + 1} ---")
|
||||
result = processor.process_pipeline(transcript)
|
||||
print(f"Result: {result.model_dump_json(indent=2)}")
|
||||
print("\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_llm_pipeline()
|
||||
@@ -0,0 +1,135 @@
|
||||
import shutil
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from src.llm.models import CharacterStateUpdate, InventoryChange, LoreUpdate
|
||||
from src.persistence.characters import get_character_state, update_character_state
|
||||
from src.persistence.lore import update_lore
|
||||
|
||||
|
||||
class TestPersistence(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Clear data directories before each test
|
||||
if Path("data/lore").exists():
|
||||
shutil.rmtree("data/lore")
|
||||
if Path("data/chars").exists():
|
||||
shutil.rmtree("data/chars")
|
||||
|
||||
def test_lore_update_npc(self):
|
||||
update = LoreUpdate(
|
||||
category="NPC",
|
||||
entity_name="Grog",
|
||||
content="Grog loves ale.",
|
||||
context="Conversation with Grog at the tavern.",
|
||||
)
|
||||
path = update_lore(update)
|
||||
self.assertTrue(Path(path).exists())
|
||||
with open(path, "r") as f:
|
||||
content = f.read()
|
||||
self.assertIn("- Grog loves ale.", content)
|
||||
|
||||
def test_lore_update_location(self):
|
||||
update = LoreUpdate(
|
||||
category="Location",
|
||||
entity_name="Waterdeep",
|
||||
content="A bustling city of splendor.",
|
||||
context="General world info.",
|
||||
)
|
||||
path = update_lore(update)
|
||||
self.assertTrue(Path(path).exists())
|
||||
with open(path, "r") as f:
|
||||
content = f.read()
|
||||
self.assertIn("- A bustling city of splendor.", content)
|
||||
|
||||
def test_lore_update_timeline(self):
|
||||
update = LoreUpdate(
|
||||
category="Plot",
|
||||
entity_name=None,
|
||||
content="The party defeated the goblins.",
|
||||
context="After the first encounter.",
|
||||
)
|
||||
path = update_lore(update)
|
||||
self.assertTrue(Path(path).exists())
|
||||
self.assertEqual(Path(path).name, "Timeline.md")
|
||||
with open(path, "r") as f:
|
||||
content = f.read()
|
||||
self.assertIn("- The party defeated the goblins.", content)
|
||||
|
||||
def test_character_update_hp(self):
|
||||
update = CharacterStateUpdate(
|
||||
character_name="Grog",
|
||||
hp_change=-10,
|
||||
status_effects_added=[],
|
||||
status_effects_removed=[],
|
||||
inventory_changes=[],
|
||||
)
|
||||
update_character_state(update)
|
||||
state = get_character_state("Grog")
|
||||
# Default HP is 0, so 0 - 10 = -10
|
||||
self.assertEqual(state["stats"]["hp"], -10)
|
||||
|
||||
def test_character_update_status_effects(self):
|
||||
update = CharacterStateUpdate(
|
||||
character_name="Grog",
|
||||
hp_change=None,
|
||||
status_effects_added=["Blinded"],
|
||||
status_effects_removed=[],
|
||||
inventory_changes=[],
|
||||
)
|
||||
update_character_state(update)
|
||||
state = get_character_state("Grog")
|
||||
self.assertIn("Blinded", state["status_effects"])
|
||||
|
||||
update2 = CharacterStateUpdate(
|
||||
character_name="Grog",
|
||||
hp_change=None,
|
||||
status_effects_added=[],
|
||||
status_effects_removed=["Blinded"],
|
||||
inventory_changes=[],
|
||||
)
|
||||
update_character_state(update2)
|
||||
state = get_character_state("Grog")
|
||||
self.assertNotIn("Blinded", state["status_effects"])
|
||||
|
||||
def test_character_update_inventory(self):
|
||||
update = CharacterStateUpdate(
|
||||
character_name="Grog",
|
||||
hp_change=None,
|
||||
status_effects_added=[],
|
||||
status_effects_removed=[],
|
||||
inventory_changes=[
|
||||
InventoryChange(item="Health Potion", quantity=2, action="added"),
|
||||
InventoryChange(item="Greatsword", quantity=1, action="added"),
|
||||
],
|
||||
)
|
||||
update_character_state(update)
|
||||
state = get_character_state("Grog")
|
||||
|
||||
inventory = state["inventory"]
|
||||
self.assertEqual(len(inventory), 2)
|
||||
self.assertEqual(inventory[0]["item"], "Health Potion")
|
||||
self.assertEqual(inventory[0]["quantity"], 2)
|
||||
|
||||
# Add more of the same item
|
||||
update2 = CharacterStateUpdate(
|
||||
character_name="Grog",
|
||||
hp_change=None,
|
||||
status_effects_added=[],
|
||||
status_effects_removed=[],
|
||||
inventory_changes=[
|
||||
InventoryChange(item="Health Potion", quantity=1, action="added")
|
||||
],
|
||||
)
|
||||
update_character_state(update2)
|
||||
state = get_character_state("Grog")
|
||||
|
||||
inventory = state["inventory"]
|
||||
# Should still be 2 unique items
|
||||
self.assertEqual(len(inventory), 2)
|
||||
# Health Potion should now be 3
|
||||
hp_potion = next(item for item in inventory if item["item"] == "Health Potion")
|
||||
self.assertEqual(hp_potion["quantity"], 3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user