Spaces:
Running
Running
<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> |