Comprehensive Guide to Building an AI-Powered Story Generator App
Transform Your Ideas into Interactive Stories with Images, Voice Narration, and Quizzes
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.
- Download XAMPP from the official website: Apache Friends
- Install XAMPP by following the on-screen instructions.
- 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.
- Open phpMyAdmin by navigating to http://localhost/phpmyadmin/.
- Click on "New" to create a new database.
- Name the database
story_appand click "Create". - 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
- Place the project folder within the XAMPP
htdocsdirectory (e.g.,C:\xampp\htdocs\StoryGenerator). - Start Apache and MySQL modules via the XAMPP Control Panel.
- Access the application by navigating to http://localhost/StoryGenerator/index.html in your web browser.
5.2 Testing Functionality
- Enter an idea or prompt into the input field.
- Click "Generate Story" to initiate story creation.
- Once the story is generated, view the related images and listen to the voice narration.
- Watch the generated video combining images, narration, and background music.
- 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.phpmatch 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.mp3anddemo_video.mp4are correctly placed in theassetsdirectory.
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