Test-6 / index.html
Holycanolies123's picture
Update index.html
211f1dd verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>App Creator AI - Hugging Face Edition</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/lib/core.js"></script>
<script src="https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/lib/languages/javascript.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/lib/languages/html.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/lib/languages/css.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/styles/github.css">
<style>
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #5D5CDE;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #4a49b0;
}
/* Dark mode adjustments */
.dark .hljs {
background: #2d2d2d;
color: #ccc;
}
.dark .hljs-tag,
.dark .hljs-keyword {
color: #e78c45;
}
.dark .hljs-title,
.dark .hljs-class,
.dark .hljs-section {
color: #e7c547;
}
.dark .hljs-string {
color: #b9ca4a;
}
.dark .hljs-attr {
color: #70c0b1;
}
</style>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: '#5D5CDE',
'primary-dark': '#4a49b0',
'primary-light': '#7a79e6',
},
}
}
}
</script>
</head>
<body class="min-h-screen bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-200">
<div class="container mx-auto px-4 py-6 max-w-6xl">
<header class="mb-8 text-center">
<h1 class="text-3xl font-bold text-primary dark:text-primary-light mb-2">App Creator AI</h1>
<p class="text-gray-600 dark:text-gray-400">Describe your app and I'll generate the code for you</p>
</header>
<main class="space-y-8">
<!-- API Key Input -->
<section class="space-y-4">
<h2 class="text-xl font-semibold">0. Setup Hugging Face API</h2>
<div class="bg-gray-100 dark:bg-gray-800 rounded-md p-4">
<p class="mb-4 text-sm">You need a free Hugging Face API token to use this app. <a href="https://huggingface.co/settings/tokens" target="_blank" class="text-primary dark:text-primary-light underline">Get your token here</a>.</p>
<div class="flex flex-col md:flex-row gap-4">
<input type="password" id="apiKeyInput" placeholder="Paste your Hugging Face API token here" class="flex-grow p-2 text-base border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-primary">
<button id="saveApiKeyBtn" class="px-4 py-2 bg-primary hover:bg-primary-dark text-white font-medium rounded-md transition-colors duration-200">Save Token</button>
</div>
<p id="apiKeyStatus" class="mt-2 text-sm text-gray-500 dark:text-gray-400">No API token saved</p>
</div>
</section>
<!-- App Description Input -->
<section class="space-y-4">
<div class="flex justify-between items-center">
<h2 class="text-xl font-semibold">1. Describe Your App</h2>
<div class="flex items-center space-x-2">
<label for="modelSelect" class="text-sm">AI Model:</label>
<select id="modelSelect" class="bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md px-3 py-1 text-base focus:outline-none focus:ring-2 focus:ring-primary">
<option value="mistralai/Mistral-7B-Instruct-v0.2" selected>Mistral-7B-Instruct</option>
<option value="google/gemma-7b-it">Gemma-7B-Instruct</option>
<option value="meta-llama/Llama-2-7b-chat-hf">Llama-2-7B-Chat</option>
<option value="bigcode/starcoder2-15b">StarCoder2-15B</option>
</select>
</div>
</div>
<textarea id="appDescription" rows="5" placeholder="Describe the app you want to create in detail. For example: 'Create a to-do list app with the ability to add, remove, and mark tasks as complete. The app should have a clean design with a dark mode option.'" class="w-full p-3 text-base border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-primary resize-y"></textarea>
<button id="generateBtn" class="w-full md:w-auto px-6 py-2 bg-primary hover:bg-primary-dark text-white font-medium rounded-md transition-colors duration-200 flex items-center justify-center">
<span id="generateBtnText">Generate App</span>
<svg id="generateBtnSpinner" class="animate-spin ml-2 h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</button>
</section>
<!-- Results Section (hidden initially) -->
<section id="resultsSection" class="hidden space-y-6">
<div class="border-t border-gray-300 dark:border-gray-700 pt-6">
<h2 class="text-xl font-semibold mb-4">2. Generated App</h2>
<!-- Tabs -->
<div class="flex border-b border-gray-300 dark:border-gray-700 mb-4">
<button id="previewTab" class="px-4 py-2 font-medium border-b-2 border-primary text-primary dark:text-primary-light">Preview</button>
<button id="codeTab" class="px-4 py-2 font-medium text-gray-600 dark:text-gray-400 hover:text-primary dark:hover:text-primary-light">Code</button>
</div>
<!-- Preview panel -->
<div id="previewPanel" class="bg-gray-100 dark:bg-gray-800 rounded-md p-4 min-h-[300px]">
<div class="bg-white dark:bg-gray-900 rounded-md w-full h-full min-h-[300px] border border-gray-300 dark:border-gray-700 overflow-hidden">
<iframe id="previewFrame" class="w-full h-[500px] border-none"></iframe>
</div>
</div>
<!-- Code panel -->
<div id="codePanel" class="hidden">
<div class="bg-gray-100 dark:bg-gray-800 rounded-md p-4">
<pre><code id="codeDisplay" class="language-html text-sm overflow-x-auto"></code></pre>
<div class="flex gap-4 mt-4">
<button id="copyCodeBtn" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded-md text-sm font-medium transition-colors duration-200 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
Copy Code
</button>
<button id="downloadCodeBtn" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded-md text-sm font-medium transition-colors duration-200 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Download HTML
</button>
</div>
</div>
</div>
</div>
</section>
<!-- Refinement Section (hidden initially) -->
<section id="refinementSection" class="hidden space-y-4 border-t border-gray-300 dark:border-gray-700 pt-6">
<h2 class="text-xl font-semibold">3. Refine Your App</h2>
<textarea id="refinementInput" rows="3" placeholder="Describe the changes you want to make to the app. For example: 'Add a search feature to filter tasks' or 'Change the color scheme to blue'." class="w-full p-3 text-base border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-primary resize-y"></textarea>
<button id="refineBtn" class="w-full md:w-auto px-6 py-2 bg-primary hover:bg-primary-dark text-white font-medium rounded-md transition-colors duration-200 flex items-center justify-center">
<span id="refineBtnText">Refine App</span>
<svg id="refineBtnSpinner" class="animate-spin ml-2 h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</button>
</section>
</main>
<footer class="mt-12 text-center text-gray-500 dark:text-gray-400 text-sm">
<p>Created with App Creator AI - Hugging Face Edition</p>
</footer>
</div>
<script>
// Dark mode detection and handling
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
if (event.matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
});
// DOM Elements
const apiKeyInput = document.getElementById('apiKeyInput');
const saveApiKeyBtn = document.getElementById('saveApiKeyBtn');
const apiKeyStatus = document.getElementById('apiKeyStatus');
const generateBtn = document.getElementById('generateBtn');
const generateBtnText = document.getElementById('generateBtnText');
const generateBtnSpinner = document.getElementById('generateBtnSpinner');
const appDescription = document.getElementById('appDescription');
const modelSelect = document.getElementById('modelSelect');
const resultsSection = document.getElementById('resultsSection');
const refinementSection = document.getElementById('refinementSection');
const codeDisplay = document.getElementById('codeDisplay');
const previewFrame = document.getElementById('previewFrame');
const copyCodeBtn = document.getElementById('copyCodeBtn');
const downloadCodeBtn = document.getElementById('downloadCodeBtn');
const previewTab = document.getElementById('previewTab');
const codeTab = document.getElementById('codeTab');
const previewPanel = document.getElementById('previewPanel');
const codePanel = document.getElementById('codePanel');
const refinementInput = document.getElementById('refinementInput');
const refineBtn = document.getElementById('refineBtn');
const refineBtnText = document.getElementById('refineBtnText');
const refineBtnSpinner = document.getElementById('refineBtnSpinner');
// State variables
let currentCode = '';
let apiKey = localStorage.getItem('hf_api_key') || '';
// Initialize API key field
if (apiKey) {
apiKeyInput.value = '••••••••••••••••••••••••••';
apiKeyStatus.textContent = 'API token saved';
apiKeyStatus.classList.add('text-green-500');
apiKeyStatus.classList.remove('text-gray-500', 'text-red-500');
}
// Save API key
saveApiKeyBtn.addEventListener('click', () => {
const newApiKey = apiKeyInput.value.trim();
if (!newApiKey) {
apiKeyStatus.textContent = 'Please enter a valid API token';
apiKeyStatus.classList.add('text-red-500');
apiKeyStatus.classList.remove('text-green-500', 'text-gray-500');
return;
}
// Save to localStorage
localStorage.setItem('hf_api_key', newApiKey);
apiKey = newApiKey;
// Update UI
apiKeyInput.value = '••••••••••••••••••••••••••';
apiKeyStatus.textContent = 'API token saved';
apiKeyStatus.classList.add('text-green-500');
apiKeyStatus.classList.remove('text-red-500', 'text-gray-500');
});
// Tab switching
previewTab.addEventListener('click', () => {
previewTab.classList.add('border-b-2', 'border-primary', 'text-primary', 'dark:text-primary-light');
previewTab.classList.remove('text-gray-600', 'dark:text-gray-400');
codeTab.classList.remove('border-b-2', 'border-primary', 'text-primary', 'dark:text-primary-light');
codeTab.classList.add('text-gray-600', 'dark:text-gray-400');
previewPanel.classList.remove('hidden');
codePanel.classList.add('hidden');
});
codeTab.addEventListener('click', () => {
codeTab.classList.add('border-b-2', 'border-primary', 'text-primary', 'dark:text-primary-light');
codeTab.classList.remove('text-gray-600', 'dark:text-gray-400');
previewTab.classList.remove('border-b-2', 'border-primary', 'text-primary', 'dark:text-primary-light');
previewTab.classList.add('text-gray-600', 'dark:text-gray-400');
codePanel.classList.remove('hidden');
previewPanel.classList.add('hidden');
});
// Copy code to clipboard
copyCodeBtn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(currentCode);
const originalText = copyCodeBtn.innerHTML;
copyCodeBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /></svg>Copied!';
setTimeout(() => {
copyCodeBtn.innerHTML = originalText;
}, 2000);
} catch (err) {
console.error('Failed to copy: ', err);
}
});
// Download code as HTML file
downloadCodeBtn.addEventListener('click', () => {
const blob = new Blob([currentCode], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'app.html';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
// Extract code from markdown response
function extractCodeFromMarkdown(markdown) {
const codeRegex = /```(?:html|)\n([\s\S]*?)```/;
const match = markdown.match(codeRegex);
return match ? match[1] : '';
}
// Update preview iframe
function updatePreview(code) {
const blob = new Blob([code], { type: 'text/html' });
const url = URL.createObjectURL(blob);
previewFrame.src = url;
}
// Helper functions for button states
function setGenerating(isGenerating) {
if (isGenerating) {
generateBtn.disabled = true;
generateBtnText.textContent = 'Generating...';
generateBtnSpinner.classList.remove('hidden');
} else {
generateBtn.disabled = false;
generateBtnText.textContent = 'Generate App';
generateBtnSpinner.classList.add('hidden');
}
}
function setRefining(isRefining) {
if (isRefining) {
refineBtn.disabled = true;
refineBtnText.textContent = 'Refining...';
refineBtnSpinner.classList.remove('hidden');
} else {
refineBtn.disabled = false;
refineBtnText.textContent = 'Refine App';
refineBtnSpinner.classList.add('hidden');
}
}
// Call Hugging Face Inference API
async function callHuggingFaceAPI(model, prompt) {
if (!apiKey) {
throw new Error('Please add your Hugging Face API token first');
}
// Prepare the prompt for different model types
let formattedPrompt = prompt;
if (model.includes('mistral')) {
formattedPrompt = `<s>[INST]${prompt}[/INST]`;
} else if (model.includes('llama')) {
formattedPrompt = `<s>[INST] ${prompt} [/INST]`;
} else if (model.includes('gemma')) {
formattedPrompt = `<start_of_turn>user\n${prompt}<end_of_turn>\n<start_of_turn>model`;
}
const response = await fetch(`https://api-inference.huggingface.co/models/${model}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
inputs: formattedPrompt,
parameters: {
max_new_tokens: 2048,
temperature: 0.7,
top_p: 0.95,
do_sample: true
}
})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API Error (${response.status}): ${errorText}`);
}
const result = await response.json();
// Handle different response formats
let generatedText = '';
if (Array.isArray(result) && result[0] && result[0].generated_text) {
generatedText = result[0].generated_text;
} else if (result.generated_text) {
generatedText = result.generated_text;
} else {
generatedText = result;
}
return generatedText;
}
// Generate App button handler
generateBtn.addEventListener('click', async () => {
const description = appDescription.value.trim();
if (!description) {
alert('Please enter a description of the app you want to create.');
return;
}
const selectedModel = modelSelect.value;
try {
setGenerating(true);
const prompt = `Create a canvas app based on this description: "${description}".
Please provide a fully functional HTML application that works as a standalone single file. Include all necessary HTML, CSS, and JavaScript in a single HTML document. Ensure the app is responsive and follows best practices for web development.
Your response MUST include a complete HTML code with proper <html>, <head>, and <body> tags, and all JavaScript and CSS should be included within this HTML file.
IMPORTANT: The code should be fully functional when copied to an HTML file and opened in a browser.`;
const response = await callHuggingFaceAPI(selectedModel, prompt);
// Extract code from response
const extractedCode = extractCodeFromMarkdown(response) || response;
if (extractedCode) {
// Check if the extracted code contains proper HTML structure
let finalCode = extractedCode;
if (!finalCode.includes('<!DOCTYPE html>') && !finalCode.includes('<html')) {
finalCode = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generated App</title>
</head>
<body>
${finalCode}
</body>
</html>`;
}
currentCode = finalCode;
// Display the code with syntax highlighting
codeDisplay.textContent = currentCode;
hljs.highlightElement(codeDisplay);
// Update the preview
updatePreview(currentCode);
// Show results and refinement sections
resultsSection.classList.remove('hidden');
refinementSection.classList.remove('hidden');
} else {
throw new Error("No usable code found in the response. Please try again with a more detailed description.");
}
} catch (err) {
console.error('Error:', err);
alert(`Error: ${err.message || 'An error occurred while generating the app'}`);
} finally {
setGenerating(false);
}
});
// Refine App button handler
refineBtn.addEventListener('click', async () => {
const refinement = refinementInput.value.trim();
if (!refinement) {
alert('Please enter a description of the changes you want to make.');
return;
}
const selectedModel = modelSelect.value;
try {
setRefining(true);
const prompt = `I have an HTML application that I want to refine. Here is the current code:
\`\`\`html
${currentCode}
\`\`\`
I want to make the following changes:
"${refinement}"
Please provide an updated version of the complete HTML code that implements these changes. Keep the core functionality and only modify what's necessary. The output should be a complete HTML file that works on its own.`;
const response = await callHuggingFaceAPI(selectedModel, prompt);
// Extract code from response
const extractedCode = extractCodeFromMarkdown(response) || response;
if (extractedCode) {
// Check if the extracted code contains proper HTML structure
let finalCode = extractedCode;
if (!finalCode.includes('<!DOCTYPE html>') && !finalCode.includes('<html')) {
finalCode = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generated App</title>
</head>
<body>
${finalCode}
</body>
</html>`;
}
currentCode = finalCode;
// Display the code with syntax highlighting
codeDisplay.textContent = currentCode;
hljs.highlightElement(codeDisplay);
// Update the preview
updatePreview(currentCode);
} else {
throw new Error("No usable code found in the response. Please try again with a more detailed description.");
}
} catch (err) {
console.error('Error:', err);
alert(`Error: ${err.message || 'An error occurred while refining the app'}`);
} finally {
setRefining(false);
}
});
</script>
</body>
</html>