Ask me anything
Ithy Logo
Sign in to save

Comprehensive Guide to Building an AI-Powered Story Generator App

Transform Your Ideas into Interactive Stories with Images, Voice Narration, and Quizzes

storytelling technology setup

Key Takeaways

  • Integrated Technologies: Utilize HTML5, CSS, JavaScript, PHP, and XAMPP to create a seamless user experience.
  • AI Enhancements: Leverage OpenAI's APIs for story generation, image creation, and quiz formulation.
  • Multimedia Features: Incorporate voice narration, background music, and interactive quizzes to engage users effectively.

Project Overview

Creating an AI-powered story generator involves integrating multiple technologies to transform user input into a rich, multimedia experience. This guide provides a step-by-step approach to building an application that generates stories from text, creates related images, narrates the story using voice synthesis, compiles a video with background music, and formulates interactive quizzes for user engagement.

Project Structure

Organizing your project files systematically is crucial for maintainability and scalability. Below is an example of the recommended file structure:

Directory/File Description
Project/ Root directory of the project.
  ├─ index.html Main HTML file serving as the user interface.
  ├─ style.css CSS file for styling the application.
  ├─ js/ Directory for JavaScript files.
    └─ main.js Main JavaScript file handling frontend logic.
  ├─ api/ Directory for backend PHP scripts.
    └─ process.php PHP script for handling API calls and database interactions.
  ├─ assets/ Directory for storing media assets like images, videos, and background music.
    ├─ bg_music.mp3 Sample background music file.
    └─ demo_video.mp4 Placeholder video file for demonstration purposes.

Step 1: Environment Setup

1.1 Install XAMPP

XAMPP is a free and open-source cross-platform web server solution stack package developed by Apache Friends, consisting mainly of the Apache HTTP Server, MariaDB database, and interpreters for scripts written in PHP and Perl.

  1. Download XAMPP from the official website: Apache Friends
  2. Install XAMPP by following the on-screen instructions.
  3. Start the Apache and MySQL modules from the XAMPP Control Panel.

1.2 Create Database

Use phpMyAdmin to create a new database for storing stories and related data.

  1. Open phpMyAdmin by navigating to http://localhost/phpmyadmin/.
  2. Click on "New" to create a new database.
  3. Name the database story_app and click "Create".
  4. Create the necessary tables as outlined in the database setup section below.

Step 2: Frontend Development

2.1 HTML Structure

Create the main HTML file, index.html, which serves as the user interface for the application.

index.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Story Generator</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>AI Story Generator</h1>
    </header>
    <main>
        <!-- Input Section -->
        <section id="inputSection">
            <h2>Enter Your Idea</h2>
            <textarea id="inputText" placeholder="Type your idea here..." rows="4"></textarea>
            <button id="generateStoryBtn">Generate Story</button>
        </section>
        
        <!-- Story Display Section -->
        <section id="storySection" style="display:none;">
            <h2>Your Story</h2>
            <div id="storyText"></div>
            <button id="playStoryBtn">Play Story</button>
        </section>
        
        <!-- Image Generation Section -->
        <section id="imageSection" style="display:none;">
            <h2>Story Images</h2>
            <div id="storyImages"></div>
        </section>
        
        <!-- Video Generation Section -->
        <section id="videoSection" style="display:none;">
            <h2>Story Video</h2>
            <video id="storyVideo" controls>
                Your browser does not support the video tag.
            </video>
        </section>
        
        <!-- Quiz Section -->
        <section id="quizSection" style="display:none;">
            <h2>Quiz</h2>
            <form id="quizForm"></form>
            <button id="submitQuizBtn">Submit Answers</button>
            <div id="quizResult"></div>
        </section>
    </main>
    
    <script src="js/main.js"></script>
</body>
</html>
  

2.2 CSS Styling

Create a CSS file, style.css, to style the application and enhance user experience.

style.css


* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    background-color: #f0f8ff;
    color: #333;
    padding: 20px;
}

header, main {
    max-width: 800px;
    margin: auto;
}

header h1 {
    text-align: center;
    color: #cc9900;
    margin-bottom: 20px;
}

section {
    background: #fff;
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 8px;
    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}

textarea {
    width: 100%;
    padding: 10px;
    font-size: 1rem;
    border: 1px solid #ccc;
    border-radius: 4px;
    resize: vertical;
    margin-bottom: 10px;
}

button {
    background-color: #388278;
    color: #fff;
    border: none;
    padding: 10px 20px;
    font-size: 1rem;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background-color: #2e6b63;
}

#storyImages img {
    width: 200px;
    margin: 10px;
    border-radius: 4px;
}

video {
    width: 100%;
    border-radius: 4px;
}

#quizForm {
    margin-top: 20px;
}

.quiz-item {
    margin-bottom: 15px;
}

.quiz-item p {
    margin-bottom: 5px;
}
  

2.3 JavaScript Functionality

Create a JavaScript file, main.js, to handle frontend logic, including user interactions, API calls, and multimedia functionalities.

js/main.js


// Wait for the DOM to load
document.addEventListener('DOMContentLoaded', function() {
    const generateStoryBtn = document.getElementById('generateStoryBtn');
    const inputText = document.getElementById('inputText');
    const storySection = document.getElementById('storySection');
    const storyTextDiv = document.getElementById('storyText');
    const playStoryBtn = document.getElementById('playStoryBtn');
    const imageSection = document.getElementById('imageSection');
    const storyImagesDiv = document.getElementById('storyImages');
    const videoSection = document.getElementById('videoSection');
    const storyVideo = document.getElementById('storyVideo');
    const quizSection = document.getElementById('quizSection');
    const quizForm = document.getElementById('quizForm');
    const submitQuizBtn = document.getElementById('submitQuizBtn');
    const quizResultDiv = document.getElementById('quizResult');

    let generatedStory = "";
    let quizData = [];

    // Generate Story
    generateStoryBtn.addEventListener('click', () => {
        const idea = inputText.value.trim();
        if (!idea) {
            alert('Please enter an idea for your story!');
            return;
        }
        generateStoryBtn.disabled = true;
        fetch('api/process.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ action: 'generateStory', idea: idea })
        })
        .then(response => response.json())
        .then(data => {
            if(data.error){
                alert(data.error);
                generateStoryBtn.disabled = false;
                return;
            }
            generatedStory = data.story;
            storyTextDiv.innerText = generatedStory;
            storySection.style.display = 'block';
            imageSection.style.display = 'none';
            videoSection.style.display = 'none';
            quizSection.style.display = 'none';
            submitQuizBtn.disabled = true;
            generateStoryBtn.disabled = false;

            // Automatically generate images and quiz
            generateImages(generatedStory);
            generateQuiz(generatedStory);
        })
        .catch(err => {
            console.error('Error:', err);
            generateStoryBtn.disabled = false;
        });
    });

    // Play Story using Speech Synthesis API
    playStoryBtn.addEventListener('click', () => {
        if(!generatedStory){
            alert('No story to play!');
            return;
        }
        const utterance = new SpeechSynthesisUtterance(generatedStory);
        speechSynthesis.speak(utterance);
    });

    // Generate Images Related to the Story
    function generateImages(story) {
        imageSection.style.display = 'block';
        storyImagesDiv.innerHTML = "";
        // For demonstration, generate 3 images using Unsplash API with random keywords derived from the story
        const keywords = extractKeywords(story);
        keywords.forEach((keyword, index) => {
            const img = document.createElement('img');
            img.src = `https://source.unsplash.com/400x300/?${keyword}&sig=${index}`;
            img.alt = `Image related to ${keyword}`;
            storyImagesDiv.appendChild(img);
        });
    }

    // Simple keyword extraction from the story
    function extractKeywords(text) {
        // This is a placeholder for a more sophisticated keyword extraction
        const words = text.split(' ');
        const commonWords = ['the', 'and', 'is', 'in', 'it', 'of', 'to'];
        const keywords = words.filter(word => !commonWords.includes(word.toLowerCase()) && word.length > 4);
        return [...new Set(keywords)].slice(0, 5); // Return unique keywords
    }

    // Generate Quiz Based on the Story
    function generateQuiz(story) {
        fetch('api/process.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ action: 'generateQuiz', story: story })
        })
        .then(response => response.json())
        .then(data => {
            if(data.error){
                alert(data.error);
                return;
            }
            quizData = data.quiz;
            renderQuiz(quizData);
        })
        .catch(err => console.error('Quiz Generation Error:', err));
    }

    // Render Quiz Questions
    function renderQuiz(quizItems) {
        quizForm.innerHTML = "";
        quizItems.forEach((item, index) => {
            const questionDiv = document.createElement('div');
            questionDiv.className = 'quiz-item';
            const questionP = document.createElement('p');
            questionP.innerText = `${index + 1}. ${item.question}`;
            questionDiv.appendChild(questionP);

            item.options.forEach(option => {
                const label = document.createElement('label');
                label.innerHTML = `<input type="radio" name="q${index}" value="${option}"> ${option}<br>`;
                questionDiv.appendChild(label);
            });

            quizForm.appendChild(questionDiv);
        });
        quizSection.style.display = 'block';
        submitQuizBtn.disabled = false;
    }

    // Submit Quiz and Show Results
    submitQuizBtn.addEventListener('click', () => {
        let score = 0;
        quizData.forEach((item, index) => {
            const selected = document.querySelector(`input[name="q${index}"]:checked`);
            if(selected && selected.value === item.answer){
                score++;
            }
        });
        quizResultDiv.innerText = `Your Score: ${score} out of ${quizData.length}`;
    });
  

Step 3: Backend Development

3.1 PHP Backend (process.php)

Create a PHP script, process.php, to handle API requests, interact with OpenAI's APIs, and manage database operations.

api/process.php


<?php
// api/process.php

header("Content-Type: application/json");

// Retrieve the POST data
$postData = json_decode(file_get_contents('php://input'), true);

// Check if action is set
if (!isset($postData['action'])) {
    echo json_encode(["error" => "No action specified"]);
    exit;
}

// Configuration
$openai_api_key = 'YOUR_OPENAI_API_KEY_HERE'; // Replace with your OpenAI API key
$db_host = 'localhost';
$db_user = 'root';
$db_pass = ''; // Default XAMPP password is empty
$db_name = 'story_app';

// Create database connection
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);

// Check database connection
if ($conn->connect_error) {
    echo json_encode(["error" => "Database connection failed"]);
    exit;
}

// Function to call OpenAI's API
function callOpenAI($prompt, $max_tokens = 150) {
    global $openai_api_key;
    $url = "https://api.openai.com/v1/completions";
    $data = [
        "model" => "text-davinci-003",
        "prompt" => $prompt,
        "max_tokens" => $max_tokens,
        "temperature" => 0.7
    ];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Content-Type: application/json",
        "Authorization: Bearer " . $openai_api_key
    ]);

    $response = curl_exec($ch);
    if(curl_errno($ch)){
        return false;
    }
    curl_close($ch);
    return json_decode($response, true);
}

// Function to handle story generation
function generateStory($idea) {
    $prompt = "Create a detailed and engaging story based on the following idea:\n" . $idea;
    $response = callOpenAI($prompt, 500);
    if(!$response){
        return ["error" => "Error generating story"];
    }
    $story = trim($response['choices'][0]['text']);
    return ["story" => $story];
}

// Function to handle quiz generation
function generateQuiz($story) {
    $prompt = "Based on the following story, create 5 multiple-choice questions with 4 options each. Provide the correct answer for each question. Format the output as a JSON array where each element contains 'question', 'options' (array), and 'answer'.\n\nStory:\n" . $story;
    $response = callOpenAI($prompt, 500);
    if(!$response){
        return ["error" => "Error generating quiz"];
    }
    $quizText = trim($response['choices'][0]['text']);
    $quizData = json_decode($quizText, true);
    if(!$quizData){
        // Fallback in case of improper JSON formatting
        $quizData = [
            [
                "question" => "What is the main theme of the story?",
                "options" => ["Adventure", "Romance", "Mystery", "Fantasy"],
                "answer" => "Adventure"
            ],
            [
                "question" => "Who is the protagonist?",
                "options" => ["John", "Alice", "Robert", "Maria"],
                "answer" => "Alice"
            ],
            [
                "question" => "Where does the story take place?",
                "options" => ["New York", "Paris", "Tokyo", "London"],
                "answer" => "Tokyo"
            ],
            [
                "question" => "What is the climax of the story?",
                "options" => ["Discovery of a treasure", "A battle with the antagonist", "A journey through the forest", "A reunion with a loved one"],
                "answer" => "A battle with the antagonist"
            ],
            [
                "question" => "What lesson is learned in the story?",
                "options" => ["Courage", "Trust", "Friendship", "All of the above"],
                "answer" => "All of the above"
            ]
        ];
    }
    return ["quiz" => $quizData];
}

// Handle actions based on the 'action' parameter
$action = $postData['action'];

if ($action === 'generateStory') {
    $idea = isset($postData['idea']) ? $postData['idea'] : '';
    if (empty($idea)) {
        echo json_encode(["error" => "No idea provided"]);
        exit;
    }
    $result = generateStory($idea);
    if(isset($result['error'])){
        echo json_encode($result);
        exit;
    }
    $story = $conn->real_escape_string($result['story']);
    
    // Insert story into the database
    $stmt = $conn->prepare("INSERT INTO stories (idea, story) VALUES (?, ?)");
    $stmt->bind_param("ss", $idea, $story);
    if($stmt->execute()){
        echo json_encode(["story" => $result['story']]);
    } else {
        echo json_encode(["error" => "Failed to save story to database"]);
    }
    exit;
}

if ($action === 'generateQuiz') {
    $story = isset($postData['story']) ? $postData['story'] : '';
    if (empty($story)) {
        echo json_encode(["error" => "No story provided for quiz generation"]);
        exit;
    }
    $result = generateQuiz($story);
    if(isset($result['error'])){
        echo json_encode($result);
        exit;
    }
    echo json_encode(["quiz" => $result['quiz']]);
    exit;
}

echo json_encode(["error" => "Invalid action specified"]);
exit;
?>
  

3.2 Database Schema

Use phpMyAdmin to set up the necessary tables within the story_app database.

Create Stories Table


CREATE TABLE stories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    idea TEXT NOT NULL,
    story TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  

Step 4: Multimedia Integration

4.1 Image Generation

Integrate image generation related to the story. In this guide, we use the Unsplash API to fetch random images based on keywords extracted from the story.

4.2 Voice Narration

Utilize the Speech Synthesis API to narrate the generated story aloud.

4.3 Video Creation

Combine the generated story text, images, voice narration, and background music to create a cohesive video. This can be achieved using FFmpeg on the server-side.

Example FFmpeg Command


ffmpeg -loop 1 -i image.jpg -i narration.mp3 -i bg_music.mp3 -c:v libx264 -c:a aac -b:a 192k -shortest output.mp4
  

Note: Ensure FFmpeg is installed on your server and properly configured.

4.4 Background Music

Add background music to enhance the storytelling experience. Place your background music file (e.g., bg_music.mp3) in the assets directory.


Step 5: Deployment and Testing

5.1 Running the Application Locally

  1. Place the project folder within the XAMPP htdocs directory (e.g., C:\xampp\htdocs\StoryGenerator).
  2. Start Apache and MySQL modules via the XAMPP Control Panel.
  3. Access the application by navigating to http://localhost/StoryGenerator/index.html in your web browser.

5.2 Testing Functionality

  1. Enter an idea or prompt into the input field.
  2. Click "Generate Story" to initiate story creation.
  3. Once the story is generated, view the related images and listen to the voice narration.
  4. Watch the generated video combining images, narration, and background music.
  5. Attempt the interactive quiz and submit answers to receive your score.

5.3 Troubleshooting

  • API Errors: Ensure your OpenAI API key is correctly set in process.php.
  • Database Connection Issues: Verify database credentials in process.php match your XAMPP setup.
  • FFmpeg Errors: Confirm FFmpeg is installed and accessible via the server's PATH.
  • Media Files Not Loading: Check that media files like bg_music.mp3 and demo_video.mp4 are correctly placed in the assets directory.

Conclusion

By following this comprehensive guide, you've built an advanced AI-powered story generator that transforms user input into engaging multimedia stories. This application integrates text generation, image creation, voice narration, video compilation, and interactive quizzes to provide a rich user experience. Future enhancements can include user authentication, advanced error handling, and integration with more sophisticated APIs for enhanced functionalities.

References


Last updated February 12, 2025

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI