diff --git a/backend/app/services/narrative/__init__.py b/backend/app/services/narrative/__init__.py new file mode 100644 index 00000000..3b069736 --- /dev/null +++ b/backend/app/services/narrative/__init__.py @@ -0,0 +1 @@ +"""Narrative Layer — translates OASIS simulation output into story prose.""" diff --git a/backend/app/services/narrative/action_mapper.py b/backend/app/services/narrative/action_mapper.py new file mode 100644 index 00000000..b7575505 --- /dev/null +++ b/backend/app/services/narrative/action_mapper.py @@ -0,0 +1,47 @@ +"""Maps OASIS action types to narrative verbs and interpretations. + +Used by the Narrative Translator to convert raw simulation actions +(`CREATE_POST`, `LIKE_POST`, etc.) into human-readable story language. +""" + +ACTION_TO_VERB = { + "CREATE_POST": "speaks", + "LIKE_POST": "agrees with", + "REPOST": "spreads word of", + "QUOTE_POST": "responds to", + "FOLLOW": "shows loyalty to", + "DO_NOTHING": "observes in silence", + "CREATE_COMMENT": "engages with", + "DISLIKE_POST": "disapproves of", + "LIKE_COMMENT": "validates", + "DISLIKE_COMMENT": "dismisses", + "SEARCH_POSTS": "investigates", + "SEARCH_USER": "seeks out", + "MUTE": "ignores", +} + +ACTION_TO_NARRATIVE = { + "CREATE_POST": "Character speaks, declares, or announces", + "LIKE_POST": "Character agrees, supports, or nods", + "REPOST": "Character spreads rumor, amplifies, or gossips", + "QUOTE_POST": "Character responds, debates, or challenges", + "FOLLOW": "Character allies with or shows loyalty to", + "DO_NOTHING": "Character reflects, observes, or waits", + "CREATE_COMMENT": "Character engages in dialogue", + "DISLIKE_POST": "Character opposes, confronts, or disapproves", + "LIKE_COMMENT": "Character validates a response", + "DISLIKE_COMMENT": "Character dismisses or mocks", + "SEARCH_POSTS": "Character investigates or seeks information", + "SEARCH_USER": "Character seeks out a specific person", + "MUTE": "Character avoids, ignores, or shuns", +} + + +def map_action_to_verb(action_type: str) -> str: + """Return a narrative verb phrase for an OASIS action type.""" + return ACTION_TO_VERB.get(action_type, "does something") + + +def get_narrative_context(action_type: str) -> str: + """Return a longer narrative interpretation for an OASIS action type.""" + return ACTION_TO_NARRATIVE.get(action_type, "Character takes an unknown action") diff --git a/backend/tests/__init__.py b/backend/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/tests/test_action_mapper.py b/backend/tests/test_action_mapper.py new file mode 100644 index 00000000..edc2fd32 --- /dev/null +++ b/backend/tests/test_action_mapper.py @@ -0,0 +1,21 @@ +from app.services.narrative.action_mapper import map_action_to_verb, get_narrative_context + + +def test_create_post_maps_to_speech(): + result = map_action_to_verb("CREATE_POST") + assert result == "speaks" + + +def test_like_post_maps_to_agreement(): + result = map_action_to_verb("LIKE_POST") + assert result == "agrees with" + + +def test_unknown_action_returns_fallback(): + result = map_action_to_verb("UNKNOWN_ACTION") + assert result == "does something" + + +def test_get_narrative_context_returns_interpretation(): + ctx = get_narrative_context("REPOST") + assert "rumor" in ctx.lower() or "amplifies" in ctx.lower()