story-ai-2.0 / templates /index.html
qdqd's picture
Upload 2 files
226c02b verified
raw
history blame
14.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wattpad Story Generator</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<nav class="navbar">
<div class="nav-container">
<div class="logo">
<i class="fas fa-book-open"></i>
<h1>Story<span>AI</span></h1>
</div>
<div class="nav-links">
<a href="#" class="active"><i class="fas fa-magic"></i> Generate</a>
<a href="#"><i class="fas fa-book"></i> Library</a>
</div>
</div>
</nav>
<div class="container">
<main>
<div class="story-generator">
<div class="input-section">
<h2><i class="fas fa-feather-alt"></i> Create Your Story</h2>
<p class="subtitle">Transform your ideas into captivating stories</p>
<div class="input-container">
<div class="input-group">
<div class="input-wrapper">
<i class="fas fa-pencil-alt input-icon"></i>
<input type="text" id="topic" placeholder="Enter your story topic..." required>
</div>
<button id="generate-btn">
<i class="fas fa-wand-magic-sparkles"></i>
Generate Story
</button>
</div>
<div class="mode-selector">
<div class="mode-buttons">
<button class="mode-btn active" data-mode="simple">
<i class="fas fa-bolt"></i>
Simple
</button>
<button class="mode-btn" data-mode="advanced">
<i class="fas fa-brain"></i>
Advanced
</button>
</div>
<div class="mode-note">Advanced mode takes longer to generate</div>
</div>
</div>
</div>
<div class="loading-spinner" style="display: none;">
<div class="spinner"></div>
<p><i class="fas fa-pen-fancy"></i> Crafting your story with creativity...</p>
</div>
<div class="story-container" style="display: none;">
<div class="contemplation-wrapper">
<div class="contemplation-section">
<div class="contemplation-header">
<div class="thinking-indicator">
<i class="fas fa-circle-notch fa-spin"></i>
Thinking...
</div>
<button class="toggle-contemplation" aria-label="Toggle thinking process">
<i class="fas fa-chevron-up"></i>
</button>
</div>
<div class="contemplation-content"></div>
</div>
</div>
<div class="chapter-navigation">
<button class="nav-btn" id="prev-chapter" disabled>
<i class="fas fa-chevron-left"></i> Previous Chapter
</button>
<span class="chapter-indicator">Chapter <span id="current-chapter">1</span></span>
<button class="nav-btn" id="next-chapter">
Next Chapter <i class="fas fa-chevron-right"></i>
</button>
</div>
<div class="story-header">
<div class="story-meta">
<i class="fas fa-book-open story-icon"></i>
<h3 class="story-title"></h3>
</div>
<div class="story-stats">
<span><i class="fas fa-eye"></i> 0 Reads</span>
<span><i class="fas fa-star"></i> 0 Votes</span>
<span><i class="fas fa-comment"></i> 0 Comments</span>
</div>
</div>
<div class="chapters-list">
<!-- Chapters will be dynamically added here -->
</div>
<div class="story-actions">
<button class="action-btn"><i class="fas fa-star"></i> Vote</button>
<button class="action-btn"><i class="fas fa-comment"></i> Comment</button>
<button class="action-btn"><i class="fas fa-share"></i> Share</button>
</div>
</div>
</div>
</main>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize thinking section toggle
const contemplationSection = document.querySelector('.contemplation-section');
const contemplationHeader = document.querySelector('.contemplation-header');
if (contemplationHeader) {
contemplationHeader.addEventListener('click', function() {
contemplationSection.classList.toggle('collapsed');
});
}
let currentChapter = 1;
let allChapters = [];
let currentTopic = '';
let isAdvancedMode = false;
// Mode selection handling
const modeButtons = document.querySelectorAll('.mode-btn');
modeButtons.forEach(button => {
button.addEventListener('click', function() {
modeButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
isAdvancedMode = this.dataset.mode === 'advanced';
});
});
document.getElementById('generate-btn').addEventListener('click', async () => {
const topic = document.getElementById('topic').value.trim();
if (!topic) {
alert('Please enter a topic');
return;
}
currentTopic = topic;
currentChapter = 1;
allChapters = [];
await generateChapter(topic);
});
document.getElementById('next-chapter').addEventListener('click', async () => {
// Only use the last chapter as context
const lastChapter = allChapters[allChapters.length - 1].content;
currentChapter++;
await generateChapter(currentTopic, lastChapter);
});
document.getElementById('prev-chapter').addEventListener('click', () => {
if (currentChapter > 1) {
currentChapter--;
updateChapterDisplay();
updateNavigationButtons();
}
});
async function generateChapter(topic, previousChapter = '') {
const loadingSpinner = document.querySelector('.loading-spinner');
const storyContainer = document.querySelector('.story-container');
const contemplationSection = document.querySelector('.contemplation-section');
loadingSpinner.style.display = 'flex';
storyContainer.style.display = 'none';
if (contemplationSection) {
contemplationSection.style.display = 'none';
}
try {
const response = await fetch('/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
topic,
previous_chapter: previousChapter,
chapter_number: currentChapter,
mode: isAdvancedMode ? 'advanced' : 'simple'
})
});
const data = await response.json();
if (data.error) {
throw new Error(data.error);
}
let storyContent = data.story;
if (isAdvancedMode) {
// Extract content between <contemplator> tags for thinking section
const contemplationMatch = storyContent.match(/<contemplator>([\s\S]*?)<\/contemplator>/);
if (contemplationMatch) {
const contemplation = contemplationMatch[1].trim();
const contemplationContent = document.querySelector('.contemplation-content');
if (contemplationContent) {
contemplationContent.innerHTML = contemplation
.split('\n')
.map(line => `<p>${line.trim()}</p>`)
.join('');
contemplationSection.style.display = 'block';
}
}
// Extract content between <final_answer> tags for the story
const finalAnswerMatch = storyContent.match(/<final_answer>([\s\S]*?)<\/final_answer>/);
if (finalAnswerMatch) {
storyContent = finalAnswerMatch[1].trim();
} else {
// If no final_answer tags found, use the content after removing contemplator section
storyContent = storyContent.replace(/<contemplator>[\s\S]*?<\/contemplator>/g, '').trim();
}
}
allChapters[currentChapter - 1] = formatChapter(storyContent, currentChapter);
updateChapterDisplay();
updateNavigationButtons();
loadingSpinner.style.display = 'none';
storyContainer.style.display = 'block';
document.querySelector('.story-title').textContent = topic;
} catch (error) {
alert('Error generating story: ' + error.message);
loadingSpinner.style.display = 'none';
}
}
// Toggle contemplation visibility
document.querySelector('.toggle-contemplation')?.addEventListener('click', function() {
const content = document.querySelector('.contemplation-content');
const icon = this.querySelector('i');
if (content.style.maxHeight) {
content.style.maxHeight = null;
icon.classList.replace('fa-chevron-down', 'fa-chevron-up');
} else {
content.style.maxHeight = content.scrollHeight + "px";
icon.classList.replace('fa-chevron-up', 'fa-chevron-down');
}
});
function updateChapterDisplay() {
const chaptersContainer = document.querySelector('.chapters-list');
chaptersContainer.innerHTML = '';
allChapters.forEach((chapter, index) => {
const chapterDiv = document.createElement('div');
chapterDiv.className = 'chapter-content' + (index + 1 === currentChapter ? ' active' : '');
chapterDiv.style.display = index + 1 === currentChapter ? 'block' : 'none';
chapterDiv.innerHTML = chapter.content;
chaptersContainer.appendChild(chapterDiv);
});
document.getElementById('current-chapter').textContent = currentChapter;
}
function updateNavigationButtons() {
const prevButton = document.getElementById('prev-chapter');
const nextButton = document.getElementById('next-chapter');
prevButton.disabled = currentChapter === 1;
nextButton.disabled = false;
}
function formatChapter(content, chapterNum) {
return {
content: content
.replace(/\n/g, '<br>')
.replace(/<chapter>/g, `<div class="chapter-section">`)
.replace(/<\/chapter>/g, '</div>')
.replace(/<chapter_number>(.*?)<\/chapter_number>/g, `<h4 class="chapter-title">Chapter ${chapterNum}</h4>`)
.replace(/<chapter_summary>(.*?)<\/chapter_summary>/g, '<div class="chapter-summary">$1</div>')
.replace(/<narrative_hook>(.*?)<\/narrative_hook>/g, '<div class="narrative-hook">$1</div>')
.replace(/<content_warning>(.*?)<\/content_warning>/g, '<div class="content-warning"><i class="fas fa-exclamation-triangle"></i> Content Warning: $1</div>')
};
}
});
</script>
</body>
</html>