An immersive, AI-powered interactive storytelling platform. Interactive Story allows users to generate dynamic, branching narratives where their choices genuinely shape the world, characters, and plotline.
This project consists of a Next.js frontend and a FastAPI + Google Agent Development Kit (ADK) + MongoDB backend.
The core of Interactive Story lies in its backend, which orchestrates Large Language Models (LLMs) to dynamically generate, track, and persist branching storylines in real-time.
- Framework: FastAPI
- Database: MongoDB (via Beanie ODM)
- Agent Orchestration: Google Agent Development Kit (ADK)
- Image Generation: SiliconFlow (FLUX.1-schnell) with automated AWS S3 uploads.
- Authentication: JWT via HTTP-only cookies.
The story generation is fundamentally modeled as a Graph of interconnected narrative nodes, guided by a master plan.
When a user initiates a new story, the backend triggers the StoryPlanner Agent:
- The Bottleneck Map: The AI acts as a Dungeon Master, outlining the overall narrative arc. It defines a "bottleneck map" which dictates the total number of levels/decisions it will take to reach a conclusion.
- The Branching Logic: The AI establishes the logical constraints of the world. It sets up the initial conditions and boundaries.
Once the master plan is generated, the backend triggers the NodeGenerator Agent to construct the very first scene (StoryNode).
Each step of the story is encapsulated in a StoryNode, which contains:
content: The descriptive narrative text.image_url: A dynamically generated image illustrating the scene (stored in S3).choices: A list ofChoiceobjects that the user can select from.
What makes this engine unique is that choices do not simply jump to a static piece of text—they actively mutate the world's State Variables.
During the initial planning phase, the StoryPlanner generates a list of dynamic StateVariable definitions (e.g., Hero_Health: 100, Has_Ancient_Key: False, Kingdom_Tension: 50).
When the NodeGenerator generates a StoryNode, it explicitly calculates the consequence of every single choice it offers.
Inside a Choice object:
text: What the user sees (e.g., "Attack the dragon!").next_node_id: A unique ID linking to the future outcome.story_state_variables: An updated snapshot of the world's state variables if this choice is selected.
Example Flow:
- User is at Node A. The
Kingdom_Tensionis currently50. - The user selects Choice 2: "Insult the King."
- The backend receives the request. It looks at the
Choice 2object, which specifically dictates thatKingdom_Tensionmust change to80. - The backend packages this new updated state (
Kingdom_Tension: 80) alongside the user's action and feeds it back into theNodeGeneratorAgent. - The LLM processes the new constraint and generates Node B. Because the tension is now
80, the AI alters its tone, generates a hostile scenario, and creates new choices reflecting the consequences of the user's past actions.
POST /story/create_story: Takes a prompt. Initializes the ADK Runner. TheStoryPlannergenerates the Master Plotline and State Variables. TheNodeGeneratoryields the first node. A SiliconFlow image is generated, uploaded to S3, and the entireStorydocument is saved to MongoDB.POST /story/{public_story_id}/create_node: Takes theprevious_node_idand the user'schoice_id. Looks up the expected State Variables from the chosen path, feeds them back into the LLM, and generates the next scene.GET /story/stories: Fetches all root stories associated with the authenticated User (or Guest).
Deployed via PM2 behind an Nginx reverse proxy managing port 8000 (Backend) and port 3000 (Frontend) on an AWS EC2 Ubuntu instance.
git clone https://github.com/samarth1224/InteractiveStory.git
cd InteractiveStoryThe backend requires Python 3.11+. Open a terminal and navigate to the project root.
cd Backend
python -m venv venv
# On Windows:
venv\Scripts\activate
# On Mac/Linux:
source venv/bin/activate
# Install dependencies
pip install -r requirements.txtConfigure Environment:
Copy the .env.example file to create your .env file, and fill in your Google GenAI, MongoDB, and SiliconFlow API keys.
cp .env.example .envKey points to note:
- Please make sure your MongoDB database is up and running.Make sure you copy connection string correctly.
- If you do not intend to engage in hassle of acquiring API key for SiliconFlow, you can skip it, but the images will not be generated.
- If you want to have images generated, get the SiliconFlow key than either,
- Leave the environment variables for AWS S3 section empty, this will directly take the link from the SiliconFlow servers(This is temporary link)
- Set up AWS S3 bucket and fill in the environment variables for AWS S3 section, this will upload the images to your S3 bucket and the link will be taken from there(This is permanent link)
- Please Leave the DATABASE_URL as it points to an local instance of sqlite database which is required for ADK to store session data. You dont have to do anything for this.
Run the Backend:
uvicorn app.main:app --reload --port 8000Open a new terminal window.
cd frontend
npm installConfigure Environment:
Copy the .env.example file to create your .env.local file.
cp .env.example .env.localRun the Frontend:
npm run devThe Interactive Story platform should now be accessible at http://localhost:3000!
If you want to run the Specmatic API contract tests against your live backend, follow these steps:
Docker is required to run this test. Make sure your Docker engine is running.
-
Run the Backend Server: Ensure your backend server is running on the exact port specified in your
specmatic.yamlfile. By default, this is port8000.uvicorn app.main:app --reload --port 8000
-
Generate an Access Token: The contract tests require a valid JWT token. You must first generate this token by making a
curlrequest to the register endpoint:curl -X POST "http://localhost:8000/auth/register" \ -H "Content-Type: application/json" \ -d '{"username": "testuser", "password": "testpassword"}'
Extract the
access_tokenfrom the JSON response. -
Set the Environment Variable: Set the environment variable
ACCESS_TOKENto the token you received.On Linux/macOS:
export ACCESS_TOKEN="your_token_value_here"
On Windows (PowerShell):
$env:ACCESS_TOKEN="your_token_value_here"
-
Run Specmatic: Execute the tests from the root directory using the Specmatic Docker image.
docker run --rm -v "${PWD}:/usr/src/app" --network host specmatic/specmatic test