A local standalone script-driven narrative agent built as a single Python app.
- LangGraph orchestrates turn-by-turn narrative execution.
- SQLite stores structured state (scenes, plots, memory, summaries, system state).
- Chroma handles semantic retrieval (RAG) for NPC/location/event knowledge.
- Streamlit provides the interactive UI.
+------------------------- Streamlit UI --------------------------+
| Upload Script -> Review Parse -> Create Character -> Chat Loop |
+-------------------------------+---------------------------------+
|
v
+-------------------- LangGraph Narrative Agent -------------------+
| build_prompt -> retrieve_memory -> generate_retrieval_queries |
| -> vector_retrieve -> construct_context -> generate_response |
| -> write_memory -> check_plot_completion -> check_scene_completion|
| -> update_state |
+-------------------------------+----------------------------------+
|
+--------------+--------------+
v v
SQLite (structured) Chroma (semantic)
scenes/plots/memory/summaries npc/location/event docs
/system_state + similarity retrieval
/app
database.py
vector_store.py
parser.py
agent_graph.py
state.py
rag.py
ui.py
main.py
requirements.txt
README.md
Responsible only for structured persistence.
Tables:
scenesplotsmemorysummariessystem_state
Usage in runtime:
- script parse result persistence
- current scene/plot pointer tracking
- turn memory append/read
- plot/scene summaries
- strict stage lifecycle (
upload -> parse -> character -> session)
Responsible only for semantic retrieval.
- deterministic local embedding function
- ingestion from scene/plot entities (NPC, location, events)
- top-k similarity search for context enrichment
Script ingestion logic.
- reads PDF pages
- segments pages into scenes (chunk-based)
- segments scenes into plots (marker/heuristic)
- extracts goals and entities used by state + RAG
LangGraph orchestration engine (preserved node flow).
Nodes:
build_promptretrieve_memorygenerate_retrieval_queriesvector_retrieveconstruct_contextgenerate_responsewrite_memorycheck_plot_completioncheck_scene_completionupdate_state
Storage calls are adapted to SQLite, retrieval calls to Chroma. Node sequence and responsibilities remain intact.
RAG helper pipeline:
- generate retrieval queries from user input + plot goal + events + memory tail
- classify retrieved docs into prompt sections
Progression helpers:
- plot completion evaluation
- scene completion evaluation
- next scene/plot transition calculation
Streamlit runtime.
Flow:
- Upload PDF
- Parse and review scene structure
- Create character
- Start narrative chat session
- Display scene/plot/progress and retrieved knowledge
For each chat message:
User input
-> build_prompt
-> retrieve_memory (SQLite)
-> generate_retrieval_queries
-> vector_retrieve (Chroma)
-> construct_context
-> generate_response
-> write_memory (SQLite)
-> check_plot_completion
-> check_scene_completion
-> update_state (SQLite)
-
SQLite: canonical structured runtime state.
- scene and plot status/progress
- chat memory turns
- summaries
- global system stage and active pointers
-
Chroma: semantic similarity only.
- vectorized knowledge docs
- retrieval for context augmentation
This separation keeps deterministic state operations isolated from semantic search operations.
Before running the project, get an API key from:
https://build.nvidia.com/settings/api-keys
Then create a file named:
api_key.txtPlace it in the project root directory and paste your API key inside (only the key, no extra spaces, utf-8 encoding).
Once the API key is set up, create and activate a virtual environment:
python -m venv .venv
. .venv/Scripts/activate # Windows PowerShell: .\.venv\Scripts\Activate.ps1
pip install -r requirements.txtstreamlit run main.pyOpen the URL shown by Streamlit (usually http://localhost:8501).
- This project is designed for local standalone execution.
- All state is persisted locally (
narrative.dband.chroma/).
A new test/ directory has been added.
These scripts all use mock inputs + print outputs, allowing you to manually verify whether the results match expectations.
Directory contents (each file except app/ui.py has a corresponding test):
-
test/test_llm_generate.py: Tests the raw LLM API call (streaming behavior, thinking/reasoning/content parsing).⚠️ Before running this test, make sureapi_key.txthas been created and configured as described in the Setup section.⚠️ All LLM invocation logic in the project must stay aligned with this file.Any changes to request payload, headers, or streaming parsing should be validated here first.
-
test/test_init.py: Tests importingapp/__init__.py -
test/test_database.py: Testsapp/database.py(database creation, insert, read, state updates) -
test/test_parser.py: Testsapp/parser.py(mock page parsing for Scene/Plot) -
test/test_rag.py: Testsapp/rag.py(query generation and knowledge classification) -
test/test_state.py: Testsapp/state.py(plot/scene progression and transitions) -
test/test_vector_store.py: Testsapp/vector_store.py(insertion and retrieval) -
test/test_agent_graph.py: Testsapp/agent_graph.py(complete single-turn workflow) -
test/test_main.py: Testsmain.pyimport and entry-point availability -
test/run_all.py: Executes all test scripts sequentially
Run individually:
python test/test_llm_generate.py
python test/test_database.py
python test/test_parser.py
python test/test_agent_graph.pyRun all at once:
python test/run_all.py