Spaces:
Build error
Build error
Deploy Gradio app with multiple files
Browse files- app.py +320 -0
- config.py +137 -0
- models.py +858 -0
- requirements.txt +43 -0
- utils.py +176 -0
app.py
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
import zipfile
|
| 5 |
+
import tempfile
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from typing import Dict, List, Tuple, Optional
|
| 8 |
+
import shutil
|
| 9 |
+
from utils import FileHandler, PreviewManager
|
| 10 |
+
from models import QwenWebsiteBuilder
|
| 11 |
+
from config import SUPPORTED_FILES, DEFAULT_PROMPT
|
| 12 |
+
|
| 13 |
+
class AIWebsiteBuilder:
|
| 14 |
+
def __init__(self):
|
| 15 |
+
self.file_handler = FileHandler()
|
| 16 |
+
self.preview_manager = PreviewManager()
|
| 17 |
+
self.model = QwenWebsiteBuilder()
|
| 18 |
+
self.current_project = None
|
| 19 |
+
self.project_history = []
|
| 20 |
+
|
| 21 |
+
def create_website(self, prompt: str, project_name: str) -> Tuple[str, str, str]:
|
| 22 |
+
"""Generate a complete website based on user prompt"""
|
| 23 |
+
try:
|
| 24 |
+
# Generate website files
|
| 25 |
+
files = self.model.generate_website(prompt, project_name)
|
| 26 |
+
|
| 27 |
+
# Create project directory
|
| 28 |
+
project_path = self.file_handler.create_project(project_name, files)
|
| 29 |
+
self.current_project = project_path
|
| 30 |
+
|
| 31 |
+
# Generate preview URL
|
| 32 |
+
preview_url = self.preview_manager.create_preview(project_path)
|
| 33 |
+
|
| 34 |
+
# Create download zip
|
| 35 |
+
zip_path = self.file_handler.create_zip(project_path)
|
| 36 |
+
|
| 37 |
+
# Update history
|
| 38 |
+
self.project_history.append({
|
| 39 |
+
"name": project_name,
|
| 40 |
+
"prompt": prompt,
|
| 41 |
+
"path": project_path,
|
| 42 |
+
"files": list(files.keys())
|
| 43 |
+
})
|
| 44 |
+
|
| 45 |
+
return f"✅ Website '{project_name}' created successfully!", preview_url, zip_path
|
| 46 |
+
|
| 47 |
+
except Exception as e:
|
| 48 |
+
return f"❌ Error: {str(e)}", "", ""
|
| 49 |
+
|
| 50 |
+
def update_file(self, project_name: str, filename: str, content: str) -> str:
|
| 51 |
+
"""Update a specific file in the project"""
|
| 52 |
+
try:
|
| 53 |
+
if self.current_project:
|
| 54 |
+
file_path = self.current_project / filename
|
| 55 |
+
with open(file_path, 'w', encoding='utf-8') as f:
|
| 56 |
+
f.write(content)
|
| 57 |
+
|
| 58 |
+
# Update preview
|
| 59 |
+
preview_url = self.preview_manager.update_preview(self.current_project)
|
| 60 |
+
return f"✅ File '{filename}' updated successfully! Preview refreshed."
|
| 61 |
+
else:
|
| 62 |
+
return "❌ No active project. Please create a website first."
|
| 63 |
+
except Exception as e:
|
| 64 |
+
return f"❌ Error updating file: {str(e)}"
|
| 65 |
+
|
| 66 |
+
def get_project_files(self) -> Dict[str, str]:
|
| 67 |
+
"""Get all files in current project"""
|
| 68 |
+
if self.current_project:
|
| 69 |
+
return self.file_handler.get_project_files(self.current_project)
|
| 70 |
+
return {}
|
| 71 |
+
|
| 72 |
+
def get_file_content(self, filename: str) -> str:
|
| 73 |
+
"""Get content of a specific file"""
|
| 74 |
+
if self.current_project:
|
| 75 |
+
return self.file_handler.get_file_content(self.current_project, filename)
|
| 76 |
+
return ""
|
| 77 |
+
|
| 78 |
+
def get_project_history(self) -> List[Dict]:
|
| 79 |
+
"""Get project generation history"""
|
| 80 |
+
return self.project_history
|
| 81 |
+
|
| 82 |
+
# Initialize the builder
|
| 83 |
+
builder = AIWebsiteBuilder()
|
| 84 |
+
|
| 85 |
+
def create_interface():
|
| 86 |
+
with gr.Blocks(
|
| 87 |
+
title="AI Website Builder",
|
| 88 |
+
theme=gr.themes.Soft(),
|
| 89 |
+
css="""
|
| 90 |
+
.header {
|
| 91 |
+
text-align: center;
|
| 92 |
+
padding: 20px;
|
| 93 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 94 |
+
color: white;
|
| 95 |
+
border-radius: 10px;
|
| 96 |
+
margin-bottom: 20px;
|
| 97 |
+
}
|
| 98 |
+
.file-editor {
|
| 99 |
+
border: 1px solid #ddd;
|
| 100 |
+
border-radius: 5px;
|
| 101 |
+
}
|
| 102 |
+
.preview-frame {
|
| 103 |
+
border: 2px solid #667eea;
|
| 104 |
+
border-radius: 5px;
|
| 105 |
+
min-height: 600px;
|
| 106 |
+
}
|
| 107 |
+
""",
|
| 108 |
+
head="""
|
| 109 |
+
<style>
|
| 110 |
+
.header a {
|
| 111 |
+
color: white;
|
| 112 |
+
text-decoration: underline;
|
| 113 |
+
}
|
| 114 |
+
</style>
|
| 115 |
+
"""
|
| 116 |
+
) as demo:
|
| 117 |
+
|
| 118 |
+
with gr.Row():
|
| 119 |
+
gr.HTML("""
|
| 120 |
+
<div class="header">
|
| 121 |
+
<h1>🚀 AI Website Builder</h1>
|
| 122 |
+
<p>Powered by Qwen AI - Build complete websites with multiple files instantly!</p>
|
| 123 |
+
<p><small>Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></small></p>
|
| 124 |
+
</div>
|
| 125 |
+
""")
|
| 126 |
+
|
| 127 |
+
with gr.Tabs() as tabs:
|
| 128 |
+
# Tab 1: Create Website
|
| 129 |
+
with gr.TabItem("🏗️ Create Website", id="create"):
|
| 130 |
+
with gr.Row():
|
| 131 |
+
with gr.Column(scale=2):
|
| 132 |
+
project_name = gr.Textbox(
|
| 133 |
+
label="Project Name",
|
| 134 |
+
placeholder="my-awesome-website",
|
| 135 |
+
value="my-website"
|
| 136 |
+
)
|
| 137 |
+
prompt = gr.Textbox(
|
| 138 |
+
label="Website Description",
|
| 139 |
+
placeholder=DEFAULT_PROMPT,
|
| 140 |
+
lines=4,
|
| 141 |
+
value=DEFAULT_PROMPT
|
| 142 |
+
)
|
| 143 |
+
create_btn = gr.Button("🚀 Generate Website", variant="primary", size="lg")
|
| 144 |
+
|
| 145 |
+
with gr.Column(scale=1):
|
| 146 |
+
gr.Markdown("""
|
| 147 |
+
### 📝 Tips:
|
| 148 |
+
- Be specific about design preferences
|
| 149 |
+
- Mention required features
|
| 150 |
+
- Specify any frameworks (React, Vue, etc.)
|
| 151 |
+
- Include color schemes if desired
|
| 152 |
+
|
| 153 |
+
### 🎯 Examples:
|
| 154 |
+
- "Create a portfolio website for a photographer with gallery"
|
| 155 |
+
- "Build an e-commerce site for selling handmade crafts"
|
| 156 |
+
- "Design a landing page for a SaaS product"
|
| 157 |
+
""")
|
| 158 |
+
|
| 159 |
+
with gr.Row():
|
| 160 |
+
status_msg = gr.Textbox(label="Status", interactive=False)
|
| 161 |
+
preview_url = gr.Textbox(label="Preview URL", interactive=False)
|
| 162 |
+
download_link = gr.File(label="Download ZIP", visible=False)
|
| 163 |
+
|
| 164 |
+
# Preview iframe
|
| 165 |
+
preview_frame = gr.HTML(
|
| 166 |
+
label="Live Preview",
|
| 167 |
+
visible=False,
|
| 168 |
+
elem_classes=["preview-frame"]
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
create_btn.click(
|
| 172 |
+
fn=builder.create_website,
|
| 173 |
+
inputs=[prompt, project_name],
|
| 174 |
+
outputs=[status_msg, preview_url, download_link]
|
| 175 |
+
).then(
|
| 176 |
+
fn=lambda url: f'<iframe src="{url}" width="100%" height="600px" class="preview-frame"></iframe>' if url else "",
|
| 177 |
+
inputs=[preview_url],
|
| 178 |
+
outputs=[preview_frame],
|
| 179 |
+
js="(url) => url ? document.querySelector('.preview-frame').parentElement.style.display = 'block' : null"
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
# Tab 2: Code Editor
|
| 183 |
+
with gr.TabItem("✏️ Code Editor", id="editor"):
|
| 184 |
+
with gr.Row():
|
| 185 |
+
with gr.Column(scale=1):
|
| 186 |
+
file_list = gr.Dropdown(
|
| 187 |
+
label="Select File",
|
| 188 |
+
choices=[],
|
| 189 |
+
interactive=True
|
| 190 |
+
)
|
| 191 |
+
refresh_files_btn = gr.Button("🔄 Refresh Files")
|
| 192 |
+
|
| 193 |
+
with gr.Column(scale=2):
|
| 194 |
+
code_editor = gr.Code(
|
| 195 |
+
label="Edit Code",
|
| 196 |
+
language="html",
|
| 197 |
+
lines=20,
|
| 198 |
+
interactive=True
|
| 199 |
+
)
|
| 200 |
+
update_btn = gr.Button("💾 Save Changes", variant="primary")
|
| 201 |
+
editor_status = gr.Textbox(label="Status", interactive=False)
|
| 202 |
+
|
| 203 |
+
# File selection
|
| 204 |
+
def update_file_list():
|
| 205 |
+
files = builder.get_project_files()
|
| 206 |
+
return gr.Dropdown(choices=list(files.keys()), value=list(files.keys())[0] if files else None)
|
| 207 |
+
|
| 208 |
+
def load_file_content(filename):
|
| 209 |
+
if filename:
|
| 210 |
+
content = builder.get_file_content(filename)
|
| 211 |
+
# Detect language
|
| 212 |
+
ext = Path(filename).suffix.lower()
|
| 213 |
+
lang_map = {
|
| 214 |
+
'.html': 'html',
|
| 215 |
+
'.css': 'css',
|
| 216 |
+
'.js': 'javascript',
|
| 217 |
+
'.json': 'json',
|
| 218 |
+
'.md': 'markdown',
|
| 219 |
+
'.py': 'python',
|
| 220 |
+
'.jsx': 'jsx',
|
| 221 |
+
'.tsx': 'typescript',
|
| 222 |
+
'.ts': 'typescript'
|
| 223 |
+
}
|
| 224 |
+
return content, lang_map.get(ext, 'html')
|
| 225 |
+
return "", "html"
|
| 226 |
+
|
| 227 |
+
refresh_files_btn.click(
|
| 228 |
+
fn=update_file_list,
|
| 229 |
+
outputs=[file_list]
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
file_list.change(
|
| 233 |
+
fn=load_file_content,
|
| 234 |
+
inputs=[file_list],
|
| 235 |
+
outputs=[code_editor, code_editor]
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
update_btn.click(
|
| 239 |
+
fn=builder.update_file,
|
| 240 |
+
inputs=[project_name, file_list, code_editor],
|
| 241 |
+
outputs=[editor_status]
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
# Tab 3: Project History
|
| 245 |
+
with gr.TabItem("📚 History", id="history"):
|
| 246 |
+
history_display = gr.Dataframe(
|
| 247 |
+
headers=["Project Name", "Prompt", "Files"],
|
| 248 |
+
datatype=["str", "str", "str"],
|
| 249 |
+
label="Previous Projects"
|
| 250 |
+
)
|
| 251 |
+
refresh_history_btn = gr.Button("🔄 Refresh History")
|
| 252 |
+
|
| 253 |
+
def refresh_history():
|
| 254 |
+
history = builder.get_project_history()
|
| 255 |
+
if history:
|
| 256 |
+
data = []
|
| 257 |
+
for project in history:
|
| 258 |
+
data.append([
|
| 259 |
+
project["name"],
|
| 260 |
+
project["prompt"][:50] + "..." if len(project["prompt"]) > 50 else project["prompt"],
|
| 261 |
+
", ".join(project["files"])
|
| 262 |
+
])
|
| 263 |
+
return data
|
| 264 |
+
return []
|
| 265 |
+
|
| 266 |
+
refresh_history_btn.click(
|
| 267 |
+
fn=refresh_history,
|
| 268 |
+
outputs=[history_display]
|
| 269 |
+
)
|
| 270 |
+
|
| 271 |
+
# Tab 4: Settings
|
| 272 |
+
with gr.TabItem("⚙️ Settings", id="settings"):
|
| 273 |
+
with gr.Row():
|
| 274 |
+
with gr.Column():
|
| 275 |
+
gr.Markdown("### 🎨 Theme Settings")
|
| 276 |
+
theme_choice = gr.Radio(
|
| 277 |
+
choices=["Modern", "Minimal", "Colorful", "Dark"],
|
| 278 |
+
value="Modern",
|
| 279 |
+
label="Default Theme"
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
gr.Markdown("### 🚀 Advanced Options")
|
| 283 |
+
use_react = gr.Checkbox(label="Use React Framework", value=False)
|
| 284 |
+
use_typescript = gr.Checkbox(label="Use TypeScript", value=False)
|
| 285 |
+
include_tests = gr.Checkbox(label="Include Test Files", value=False)
|
| 286 |
+
|
| 287 |
+
with gr.Column():
|
| 288 |
+
gr.Markdown("### 📁 Supported File Types")
|
| 289 |
+
gr.Markdown(f"""
|
| 290 |
+
{', '.join([f'`.{ext}`' for ext in SUPPORTED_FILES])}
|
| 291 |
+
|
| 292 |
+
### 🔧 Features:
|
| 293 |
+
- Multi-file project generation
|
| 294 |
+
- Live preview with hot reload
|
| 295 |
+
- Code editor with syntax highlighting
|
| 296 |
+
- Project history tracking
|
| 297 |
+
- ZIP download support
|
| 298 |
+
- Responsive design
|
| 299 |
+
- SEO optimization
|
| 300 |
+
- Performance optimization
|
| 301 |
+
""")
|
| 302 |
+
|
| 303 |
+
# Auto-refresh file list when switching to editor tab
|
| 304 |
+
tabs.select(
|
| 305 |
+
fn=update_file_list,
|
| 306 |
+
inputs=[],
|
| 307 |
+
outputs=[file_list],
|
| 308 |
+
show_progress=False
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
return demo
|
| 312 |
+
|
| 313 |
+
if __name__ == "__main__":
|
| 314 |
+
demo = create_interface()
|
| 315 |
+
demo.launch(
|
| 316 |
+
server_name="0.0.0.0",
|
| 317 |
+
server_port=7860,
|
| 318 |
+
share=True,
|
| 319 |
+
show_error=True
|
| 320 |
+
)
|
config.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Configuration file for AI Website Builder
|
| 2 |
+
|
| 3 |
+
# Supported file types
|
| 4 |
+
SUPPORTED_FILES = [
|
| 5 |
+
'html', 'css', 'js', 'json', 'md', 'txt', 'xml', 'yaml', 'yml',
|
| 6 |
+
'jsx', 'tsx', 'ts', 'vue', 'svelte', 'py', 'php', 'rb', 'go',
|
| 7 |
+
'java', 'c', 'cpp', 'h', 'hpp', 'scss', 'sass', 'less',
|
| 8 |
+
'sql', 'sh', 'bat', 'ps1', 'dockerfile', 'gitignore',
|
| 9 |
+
'env', 'ini', 'cfg', 'conf', 'log', 'csv', 'svg', 'png',
|
| 10 |
+
'jpg', 'jpeg', 'gif', 'ico', 'pdf', 'doc', 'docx', 'xls',
|
| 11 |
+
'xlsx', 'ppt', 'pptx', 'zip', 'rar', 'tar', 'gz'
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
# Default prompt for new users
|
| 15 |
+
DEFAULT_PROMPT = """Create a modern portfolio website with:
|
| 16 |
+
- Hero section with animated text
|
| 17 |
+
- Project gallery with filter functionality
|
| 18 |
+
- About section with skills
|
| 19 |
+
- Contact form with validation
|
| 20 |
+
- Smooth scrolling navigation
|
| 21 |
+
- Dark/light mode toggle
|
| 22 |
+
- Responsive design for all devices
|
| 23 |
+
- Modern animations and transitions"""
|
| 24 |
+
|
| 25 |
+
# Website templates
|
| 26 |
+
WEBSITE_TEMPLATES = {
|
| 27 |
+
"portfolio": {
|
| 28 |
+
"name": "Portfolio Website",
|
| 29 |
+
"description": "Perfect for showcasing your work and skills",
|
| 30 |
+
"features": ["gallery", "about", "contact", "skills"]
|
| 31 |
+
},
|
| 32 |
+
"business": {
|
| 33 |
+
"name": "Business Website",
|
| 34 |
+
"description": "Professional website for your business",
|
| 35 |
+
"features": ["services", "about", "testimonials", "contact"]
|
| 36 |
+
},
|
| 37 |
+
"blog": {
|
| 38 |
+
"name": "Blog Website",
|
| 39 |
+
"description": "Clean and modern blog design",
|
| 40 |
+
"features": ["posts", "categories", "search", "comments"]
|
| 41 |
+
},
|
| 42 |
+
"ecommerce": {
|
| 43 |
+
"name": "E-commerce Store",
|
| 44 |
+
"description": "Online store with product catalog",
|
| 45 |
+
"features": ["products", "cart", "checkout", "search"]
|
| 46 |
+
},
|
| 47 |
+
"landing": {
|
| 48 |
+
"name": "Landing Page",
|
| 49 |
+
"description": "High-converting landing page",
|
| 50 |
+
"features": ["hero", "features", "testimonials", "cta"]
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
# Color schemes
|
| 55 |
+
COLOR_SCHEMES = {
|
| 56 |
+
"blue": {
|
| 57 |
+
"primary": "#3498db",
|
| 58 |
+
"secondary": "#2980b9",
|
| 59 |
+
"accent": "#e74c3c"
|
| 60 |
+
},
|
| 61 |
+
"red": {
|
| 62 |
+
"primary": "#e74c3c",
|
| 63 |
+
"secondary": "#c0392b",
|
| 64 |
+
"accent": "#f39c12"
|
| 65 |
+
},
|
| 66 |
+
"green": {
|
| 67 |
+
"primary": "#27ae60",
|
| 68 |
+
"secondary": "#229954",
|
| 69 |
+
"accent": "#f39c12"
|
| 70 |
+
},
|
| 71 |
+
"purple": {
|
| 72 |
+
"primary": "#9b59b6",
|
| 73 |
+
"secondary": "#8e44ad",
|
| 74 |
+
"accent": "#e74c3c"
|
| 75 |
+
},
|
| 76 |
+
"orange": {
|
| 77 |
+
"primary": "#f39c12",
|
| 78 |
+
"secondary": "#e67e22",
|
| 79 |
+
"accent": "#3498db"
|
| 80 |
+
},
|
| 81 |
+
"dark": {
|
| 82 |
+
"primary": "#34495e",
|
| 83 |
+
"secondary": "#2c3e50",
|
| 84 |
+
"accent": "#3498db"
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
# Framework options
|
| 89 |
+
FRAMEWORKS = {
|
| 90 |
+
"vanilla": {
|
| 91 |
+
"name": "Vanilla HTML/CSS/JS",
|
| 92 |
+
"description": "Pure web technologies, no frameworks"
|
| 93 |
+
},
|
| 94 |
+
"bootstrap": {
|
| 95 |
+
"name": "Bootstrap",
|
| 96 |
+
"description": "Popular CSS framework for responsive design"
|
| 97 |
+
},
|
| 98 |
+
"tailwind": {
|
| 99 |
+
"name": "Tailwind CSS",
|
| 100 |
+
"description": "Utility-first CSS framework"
|
| 101 |
+
},
|
| 102 |
+
"react": {
|
| 103 |
+
"name": "React",
|
| 104 |
+
"description": "JavaScript library for building user interfaces"
|
| 105 |
+
},
|
| 106 |
+
"vue": {
|
| 107 |
+
"name": "Vue.js",
|
| 108 |
+
"description": "Progressive JavaScript framework"
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
# Server configuration
|
| 113 |
+
SERVER_CONFIG = {
|
| 114 |
+
"host": "0.0.0.0",
|
| 115 |
+
"port": 7860,
|
| 116 |
+
"debug": True,
|
| 117 |
+
"share": True
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
# File size limits (in bytes)
|
| 121 |
+
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
|
| 122 |
+
MAX_ZIP_SIZE = 50 * 1024 * 1024 # 50MB
|
| 123 |
+
|
| 124 |
+
# Preview server settings
|
| 125 |
+
PREVIEW_CONFIG = {
|
| 126 |
+
"port_range": (8000, 9000),
|
| 127 |
+
"timeout": 30,
|
| 128 |
+
"auto_refresh": True
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
# AI model settings
|
| 132 |
+
AI_CONFIG = {
|
| 133 |
+
"model": "qwen2.5-72b-instruct",
|
| 134 |
+
"temperature": 0.7,
|
| 135 |
+
"max_tokens": 4000,
|
| 136 |
+
"timeout": 60
|
| 137 |
+
}
|
models.py
ADDED
|
@@ -0,0 +1,858 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import re
|
| 3 |
+
from typing import Dict, List, Optional
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
import random
|
| 6 |
+
|
| 7 |
+
class QwenWebsiteBuilder:
|
| 8 |
+
"""AI-powered website builder using Qwen model logic"""
|
| 9 |
+
|
| 10 |
+
def __init__(self):
|
| 11 |
+
self.templates = self._load_templates()
|
| 12 |
+
self.components = self._load_components()
|
| 13 |
+
|
| 14 |
+
def generate_website(self, prompt: str, project_name: str) -> Dict[str, str]:
|
| 15 |
+
"""Generate a complete website based on the prompt"""
|
| 16 |
+
# Parse requirements from prompt
|
| 17 |
+
requirements = self._parse_requirements(prompt)
|
| 18 |
+
|
| 19 |
+
# Generate HTML structure
|
| 20 |
+
html_content = self._generate_html(requirements, project_name)
|
| 21 |
+
|
| 22 |
+
# Generate CSS styles
|
| 23 |
+
css_content = self._generate_css(requirements)
|
| 24 |
+
|
| 25 |
+
# Generate JavaScript functionality
|
| 26 |
+
js_content = self._generate_js(requirements)
|
| 27 |
+
|
| 28 |
+
# Generate additional files based on requirements
|
| 29 |
+
files = {
|
| 30 |
+
"index.html": html_content,
|
| 31 |
+
"styles/main.css": css_content,
|
| 32 |
+
"scripts/main.js": js_content,
|
| 33 |
+
"README.md": self._generate_readme(requirements, project_name),
|
| 34 |
+
"package.json": self._generate_package_json(requirements),
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
# Add framework-specific files
|
| 38 |
+
if requirements.get("framework") == "react":
|
| 39 |
+
files.update(self._generate_react_files(requirements))
|
| 40 |
+
elif requirements.get("framework") == "vue":
|
| 41 |
+
files.update(self._generate_vue_files(requirements))
|
| 42 |
+
|
| 43 |
+
# Add additional pages if requested
|
| 44 |
+
if requirements.get("pages"):
|
| 45 |
+
for page in requirements["pages"]:
|
| 46 |
+
files.update(self._generate_page(page, requirements))
|
| 47 |
+
|
| 48 |
+
# Add assets
|
| 49 |
+
files.update(self._generate_assets(requirements))
|
| 50 |
+
|
| 51 |
+
return files
|
| 52 |
+
|
| 53 |
+
def _parse_requirements(self, prompt: str) -> Dict:
|
| 54 |
+
"""Parse user requirements from the prompt"""
|
| 55 |
+
requirements = {
|
| 56 |
+
"type": "website",
|
| 57 |
+
"design": "modern",
|
| 58 |
+
"features": [],
|
| 59 |
+
"pages": ["home"],
|
| 60 |
+
"framework": None,
|
| 61 |
+
"color_scheme": "blue",
|
| 62 |
+
"responsive": True,
|
| 63 |
+
"interactive": True
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
prompt_lower = prompt.lower()
|
| 67 |
+
|
| 68 |
+
# Detect website type
|
| 69 |
+
if "portfolio" in prompt_lower:
|
| 70 |
+
requirements["type"] = "portfolio"
|
| 71 |
+
requirements["features"].extend(["gallery", "about", "contact"])
|
| 72 |
+
elif "ecommerce" in prompt_lower or "shop" in prompt_lower:
|
| 73 |
+
requirements["type"] = "ecommerce"
|
| 74 |
+
requirements["features"].extend(["products", "cart", "checkout"])
|
| 75 |
+
elif "blog" in prompt_lower:
|
| 76 |
+
requirements["type"] = "blog"
|
| 77 |
+
requirements["features"].extend(["posts", "categories", "comments"])
|
| 78 |
+
elif "landing" in prompt_lower:
|
| 79 |
+
requirements["type"] = "landing"
|
| 80 |
+
requirements["features"].extend(["hero", "features", "cta"])
|
| 81 |
+
|
| 82 |
+
# Detect framework preferences
|
| 83 |
+
if "react" in prompt_lower:
|
| 84 |
+
requirements["framework"] = "react"
|
| 85 |
+
elif "vue" in prompt_lower:
|
| 86 |
+
requirements["framework"] = "vue"
|
| 87 |
+
elif "bootstrap" in prompt_lower:
|
| 88 |
+
requirements["framework"] = "bootstrap"
|
| 89 |
+
|
| 90 |
+
# Detect color preferences
|
| 91 |
+
colors = ["blue", "red", "green", "purple", "orange", "dark", "light"]
|
| 92 |
+
for color in colors:
|
| 93 |
+
if color in prompt_lower:
|
| 94 |
+
requirements["color_scheme"] = color
|
| 95 |
+
break
|
| 96 |
+
|
| 97 |
+
# Detect specific features
|
| 98 |
+
features_map = {
|
| 99 |
+
"contact": ["contact form", "contact"],
|
| 100 |
+
"gallery": ["gallery", "images", "photos"],
|
| 101 |
+
"navigation": ["navigation", "menu", "navbar"],
|
| 102 |
+
"search": ["search", "filter"],
|
| 103 |
+
"animation": ["animation", "animate", "transition"],
|
| 104 |
+
"responsive": ["responsive", "mobile"],
|
| 105 |
+
"dark mode": ["dark mode", "dark theme"]
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
for feature, keywords in features_map.items():
|
| 109 |
+
if any(keyword in prompt_lower for keyword in keywords):
|
| 110 |
+
requirements["features"].append(feature)
|
| 111 |
+
|
| 112 |
+
return requirements
|
| 113 |
+
|
| 114 |
+
def _generate_html(self, requirements: Dict, project_name: str) -> str:
|
| 115 |
+
"""Generate HTML structure"""
|
| 116 |
+
html_template = f"""<!DOCTYPE html>
|
| 117 |
+
<html lang="en">
|
| 118 |
+
<head>
|
| 119 |
+
<meta charset="UTF-8">
|
| 120 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 121 |
+
<title>{project_name.title()}</title>
|
| 122 |
+
<meta name="description" content="{requirements.get('description', 'A modern website built with AI')}">
|
| 123 |
+
<link rel="stylesheet" href="styles/main.css">
|
| 124 |
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
| 125 |
+
</head>
|
| 126 |
+
<body>
|
| 127 |
+
{self._generate_navigation(requirements)}
|
| 128 |
+
|
| 129 |
+
<main>
|
| 130 |
+
{self._generate_hero_section(requirements)}
|
| 131 |
+
{self._generate_features_section(requirements)}
|
| 132 |
+
{self._generate_content_sections(requirements)}
|
| 133 |
+
</main>
|
| 134 |
+
|
| 135 |
+
{self._generate_footer(requirements)}
|
| 136 |
+
|
| 137 |
+
<script src="scripts/main.js"></script>
|
| 138 |
+
</body>
|
| 139 |
+
</html>"""
|
| 140 |
+
return html_template
|
| 141 |
+
|
| 142 |
+
def _generate_css(self, requirements: Dict) -> str:
|
| 143 |
+
"""Generate CSS styles"""
|
| 144 |
+
color_scheme = requirements.get("color_scheme", "blue")
|
| 145 |
+
colors = self._get_color_palette(color_scheme)
|
| 146 |
+
|
| 147 |
+
css = f"""/* Global Styles */
|
| 148 |
+
* {{
|
| 149 |
+
margin: 0;
|
| 150 |
+
padding: 0;
|
| 151 |
+
box-sizing: border-box;
|
| 152 |
+
}}
|
| 153 |
+
|
| 154 |
+
:root {{
|
| 155 |
+
--primary-color: {colors['primary']};
|
| 156 |
+
--secondary-color: {colors['secondary']};
|
| 157 |
+
--accent-color: {colors['accent']};
|
| 158 |
+
--text-color: {colors['text']};
|
| 159 |
+
--bg-color: {colors['background']};
|
| 160 |
+
--light-bg: {colors['light_bg']};
|
| 161 |
+
}}
|
| 162 |
+
|
| 163 |
+
body {{
|
| 164 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| 165 |
+
line-height: 1.6;
|
| 166 |
+
color: var(--text-color);
|
| 167 |
+
background-color: var(--bg-color);
|
| 168 |
+
}}
|
| 169 |
+
|
| 170 |
+
/* Navigation */
|
| 171 |
+
.navbar {{
|
| 172 |
+
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
|
| 173 |
+
padding: 1rem 0;
|
| 174 |
+
position: fixed;
|
| 175 |
+
width: 100%;
|
| 176 |
+
top: 0;
|
| 177 |
+
z-index: 1000;
|
| 178 |
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
| 179 |
+
}}
|
| 180 |
+
|
| 181 |
+
.nav-container {{
|
| 182 |
+
max-width: 1200px;
|
| 183 |
+
margin: 0 auto;
|
| 184 |
+
padding: 0 2rem;
|
| 185 |
+
display: flex;
|
| 186 |
+
justify-content: space-between;
|
| 187 |
+
align-items: center;
|
| 188 |
+
}}
|
| 189 |
+
|
| 190 |
+
.nav-logo {{
|
| 191 |
+
font-size: 1.5rem;
|
| 192 |
+
font-weight: bold;
|
| 193 |
+
color: white;
|
| 194 |
+
text-decoration: none;
|
| 195 |
+
}}
|
| 196 |
+
|
| 197 |
+
.nav-menu {{
|
| 198 |
+
display: flex;
|
| 199 |
+
list-style: none;
|
| 200 |
+
gap: 2rem;
|
| 201 |
+
}}
|
| 202 |
+
|
| 203 |
+
.nav-link {{
|
| 204 |
+
color: white;
|
| 205 |
+
text-decoration: none;
|
| 206 |
+
transition: opacity 0.3s ease;
|
| 207 |
+
}}
|
| 208 |
+
|
| 209 |
+
.nav-link:hover {{
|
| 210 |
+
opacity: 0.8;
|
| 211 |
+
}}
|
| 212 |
+
|
| 213 |
+
/* Hero Section */
|
| 214 |
+
.hero {{
|
| 215 |
+
margin-top: 80px;
|
| 216 |
+
padding: 6rem 2rem;
|
| 217 |
+
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
|
| 218 |
+
color: white;
|
| 219 |
+
text-align: center;
|
| 220 |
+
}}
|
| 221 |
+
|
| 222 |
+
.hero h1 {{
|
| 223 |
+
font-size: 3rem;
|
| 224 |
+
margin-bottom: 1rem;
|
| 225 |
+
animation: fadeInUp 1s ease;
|
| 226 |
+
}}
|
| 227 |
+
|
| 228 |
+
.hero p {{
|
| 229 |
+
font-size: 1.2rem;
|
| 230 |
+
margin-bottom: 2rem;
|
| 231 |
+
animation: fadeInUp 1s ease 0.2s both;
|
| 232 |
+
}}
|
| 233 |
+
|
| 234 |
+
.cta-button {{
|
| 235 |
+
display: inline-block;
|
| 236 |
+
padding: 1rem 2rem;
|
| 237 |
+
background: var(--accent-color);
|
| 238 |
+
color: white;
|
| 239 |
+
text-decoration: none;
|
| 240 |
+
border-radius: 50px;
|
| 241 |
+
font-weight: bold;
|
| 242 |
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
| 243 |
+
animation: fadeInUp 1s ease 0.4s both;
|
| 244 |
+
}}
|
| 245 |
+
|
| 246 |
+
.cta-button:hover {{
|
| 247 |
+
transform: translateY(-2px);
|
| 248 |
+
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
|
| 249 |
+
}}
|
| 250 |
+
|
| 251 |
+
/* Features Section */
|
| 252 |
+
.features {{
|
| 253 |
+
padding: 4rem 2rem;
|
| 254 |
+
max-width: 1200px;
|
| 255 |
+
margin: 0 auto;
|
| 256 |
+
}}
|
| 257 |
+
|
| 258 |
+
.features h2 {{
|
| 259 |
+
text-align: center;
|
| 260 |
+
font-size: 2.5rem;
|
| 261 |
+
margin-bottom: 3rem;
|
| 262 |
+
color: var(--primary-color);
|
| 263 |
+
}}
|
| 264 |
+
|
| 265 |
+
.feature-grid {{
|
| 266 |
+
display: grid;
|
| 267 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
| 268 |
+
gap: 2rem;
|
| 269 |
+
}}
|
| 270 |
+
|
| 271 |
+
.feature-card {{
|
| 272 |
+
background: white;
|
| 273 |
+
padding: 2rem;
|
| 274 |
+
border-radius: 10px;
|
| 275 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
| 276 |
+
text-align: center;
|
| 277 |
+
transition: transform 0.3s ease;
|
| 278 |
+
}}
|
| 279 |
+
|
| 280 |
+
.feature-card:hover {{
|
| 281 |
+
transform: translateY(-5px);
|
| 282 |
+
}}
|
| 283 |
+
|
| 284 |
+
.feature-icon {{
|
| 285 |
+
font-size: 3rem;
|
| 286 |
+
color: var(--primary-color);
|
| 287 |
+
margin-bottom: 1rem;
|
| 288 |
+
}}
|
| 289 |
+
|
| 290 |
+
/* Footer */
|
| 291 |
+
.footer {{
|
| 292 |
+
background: var(--secondary-color);
|
| 293 |
+
color: white;
|
| 294 |
+
text-align: center;
|
| 295 |
+
padding: 2rem;
|
| 296 |
+
}}
|
| 297 |
+
|
| 298 |
+
/* Animations */
|
| 299 |
+
@keyframes fadeInUp {{
|
| 300 |
+
from {{
|
| 301 |
+
opacity: 0;
|
| 302 |
+
transform: translateY(30px);
|
| 303 |
+
}}
|
| 304 |
+
to {{
|
| 305 |
+
opacity: 1;
|
| 306 |
+
transform: translateY(0);
|
| 307 |
+
}}
|
| 308 |
+
}}
|
| 309 |
+
|
| 310 |
+
/* Responsive Design */
|
| 311 |
+
@media (max-width: 768px) {{
|
| 312 |
+
.nav-menu {{
|
| 313 |
+
flex-direction: column;
|
| 314 |
+
gap: 1rem;
|
| 315 |
+
}}
|
| 316 |
+
|
| 317 |
+
.hero h1 {{
|
| 318 |
+
font-size: 2rem;
|
| 319 |
+
}}
|
| 320 |
+
|
| 321 |
+
.feature-grid {{
|
| 322 |
+
grid-template-columns: 1fr;
|
| 323 |
+
}}
|
| 324 |
+
}}"""
|
| 325 |
+
|
| 326 |
+
return css
|
| 327 |
+
|
| 328 |
+
def _generate_js(self, requirements: Dict) -> str:
|
| 329 |
+
"""Generate JavaScript functionality"""
|
| 330 |
+
js = """// Website JavaScript
|
| 331 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 332 |
+
// Smooth scrolling for navigation links
|
| 333 |
+
const navLinks = document.querySelectorAll('.nav-link');
|
| 334 |
+
navLinks.forEach(link => {
|
| 335 |
+
link.addEventListener('click', function(e) {
|
| 336 |
+
if (this.getAttribute('href').startsWith('#')) {
|
| 337 |
+
e.preventDefault();
|
| 338 |
+
const target = document.querySelector(this.getAttribute('href'));
|
| 339 |
+
if (target) {
|
| 340 |
+
target.scrollIntoView({
|
| 341 |
+
behavior: 'smooth'
|
| 342 |
+
});
|
| 343 |
+
}
|
| 344 |
+
}
|
| 345 |
+
});
|
| 346 |
+
});
|
| 347 |
+
|
| 348 |
+
// Mobile menu toggle
|
| 349 |
+
const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
|
| 350 |
+
const navMenu = document.querySelector('.nav-menu');
|
| 351 |
+
|
| 352 |
+
if (mobileMenuBtn) {
|
| 353 |
+
mobileMenuBtn.addEventListener('click', function() {
|
| 354 |
+
navMenu.classList.toggle('active');
|
| 355 |
+
});
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
// Scroll animations
|
| 359 |
+
const observerOptions = {
|
| 360 |
+
threshold: 0.1,
|
| 361 |
+
rootMargin: '0px 0px -50px 0px'
|
| 362 |
+
};
|
| 363 |
+
|
| 364 |
+
const observer = new IntersectionObserver(function(entries) {
|
| 365 |
+
entries.forEach(entry => {
|
| 366 |
+
if (entry.isIntersecting) {
|
| 367 |
+
entry.target.style.opacity = '1';
|
| 368 |
+
entry.target.style.transform = 'translateY(0)';
|
| 369 |
+
}
|
| 370 |
+
});
|
| 371 |
+
}, observerOptions);
|
| 372 |
+
|
| 373 |
+
// Observe feature cards
|
| 374 |
+
const featureCards = document.querySelectorAll('.feature-card');
|
| 375 |
+
featureCards.forEach(card => {
|
| 376 |
+
card.style.opacity = '0';
|
| 377 |
+
card.style.transform = 'translateY(20px)';
|
| 378 |
+
card.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
|
| 379 |
+
observer.observe(card);
|
| 380 |
+
});
|
| 381 |
+
|
| 382 |
+
// Form validation
|
| 383 |
+
const forms = document.querySelectorAll('form');
|
| 384 |
+
forms.forEach(form => {
|
| 385 |
+
form.addEventListener('submit', function(e) {
|
| 386 |
+
e.preventDefault();
|
| 387 |
+
|
| 388 |
+
const formData = new FormData(form);
|
| 389 |
+
const data = Object.fromEntries(formData);
|
| 390 |
+
|
| 391 |
+
// Simple validation
|
| 392 |
+
let isValid = true;
|
| 393 |
+
const requiredFields = form.querySelectorAll('[required]');
|
| 394 |
+
|
| 395 |
+
requiredFields.forEach(field => {
|
| 396 |
+
if (!field.value.trim()) {
|
| 397 |
+
isValid = false;
|
| 398 |
+
field.classList.add('error');
|
| 399 |
+
} else {
|
| 400 |
+
field.classList.remove('error');
|
| 401 |
+
}
|
| 402 |
+
});
|
| 403 |
+
|
| 404 |
+
if (isValid) {
|
| 405 |
+
// Show success message
|
| 406 |
+
showMessage('Form submitted successfully!', 'success');
|
| 407 |
+
form.reset();
|
| 408 |
+
} else {
|
| 409 |
+
showMessage('Please fill in all required fields.', 'error');
|
| 410 |
+
}
|
| 411 |
+
});
|
| 412 |
+
});
|
| 413 |
+
|
| 414 |
+
// Utility function to show messages
|
| 415 |
+
function showMessage(message, type) {
|
| 416 |
+
const messageDiv = document.createElement('div');
|
| 417 |
+
messageDiv.className = `message ${type}`;
|
| 418 |
+
messageDiv.textContent = message;
|
| 419 |
+
messageDiv.style.cssText = `
|
| 420 |
+
position: fixed;
|
| 421 |
+
top: 20px;
|
| 422 |
+
right: 20px;
|
| 423 |
+
padding: 1rem 2rem;
|
| 424 |
+
border-radius: 5px;
|
| 425 |
+
color: white;
|
| 426 |
+
z-index: 10000;
|
| 427 |
+
animation: slideIn 0.3s ease;
|
| 428 |
+
`;
|
| 429 |
+
|
| 430 |
+
if (type === 'success') {
|
| 431 |
+
messageDiv.style.background = '#4CAF50';
|
| 432 |
+
} else {
|
| 433 |
+
messageDiv.style.background = '#f44336';
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
document.body.appendChild(messageDiv);
|
| 437 |
+
|
| 438 |
+
setTimeout(() => {
|
| 439 |
+
messageDiv.remove();
|
| 440 |
+
}, 3000);
|
| 441 |
+
}
|
| 442 |
+
});
|
| 443 |
+
|
| 444 |
+
// Add slide-in animation
|
| 445 |
+
const style = document.createElement('style');
|
| 446 |
+
style.textContent = `
|
| 447 |
+
@keyframes slideIn {
|
| 448 |
+
from {
|
| 449 |
+
transform: translateX(100%);
|
| 450 |
+
opacity: 0;
|
| 451 |
+
}
|
| 452 |
+
to {
|
| 453 |
+
transform: translateX(0);
|
| 454 |
+
opacity: 1;
|
| 455 |
+
}
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
.message {
|
| 459 |
+
animation: slideIn 0.3s ease;
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
.form-input.error {
|
| 463 |
+
border-color: #f44336;
|
| 464 |
+
}
|
| 465 |
+
`;
|
| 466 |
+
document.head.appendChild(style);"""
|
| 467 |
+
|
| 468 |
+
return js
|
| 469 |
+
|
| 470 |
+
def _generate_navigation(self, requirements: Dict) -> str:
|
| 471 |
+
"""Generate navigation HTML"""
|
| 472 |
+
return f"""<nav class="navbar">
|
| 473 |
+
<div class="nav-container">
|
| 474 |
+
<a href="#" class="nav-logo">
|
| 475 |
+
<i class="fas fa-rocket"></i> {requirements['type'].title()}
|
| 476 |
+
</a>
|
| 477 |
+
<ul class="nav-menu">
|
| 478 |
+
<li><a href="#home" class="nav-link">Home</a></li>
|
| 479 |
+
<li><a href="#features" class="nav-link">Features</a></li>
|
| 480 |
+
<li><a href="#about" class="nav-link">About</a></li>
|
| 481 |
+
<li><a href="#contact" class="nav-link">Contact</a></li>
|
| 482 |
+
</ul>
|
| 483 |
+
<button class="mobile-menu-btn">
|
| 484 |
+
<i class="fas fa-bars"></i>
|
| 485 |
+
</button>
|
| 486 |
+
</div>
|
| 487 |
+
</nav>"""
|
| 488 |
+
|
| 489 |
+
def _generate_hero_section(self, requirements: Dict) -> str:
|
| 490 |
+
"""Generate hero section HTML"""
|
| 491 |
+
return f"""<section class="hero" id="home">
|
| 492 |
+
<div class="hero-content">
|
| 493 |
+
<h1>Welcome to Your {requirements['type'].title()}</h1>
|
| 494 |
+
<p>A modern, responsive website built with AI-powered technology</p>
|
| 495 |
+
<a href="#features" class="cta-button">Get Started</a>
|
| 496 |
+
</div>
|
| 497 |
+
</section>"""
|
| 498 |
+
|
| 499 |
+
def _generate_features_section(self, requirements: Dict) -> str:
|
| 500 |
+
"""Generate features section HTML"""
|
| 501 |
+
features = requirements.get("features", ["responsive", "modern"])
|
| 502 |
+
|
| 503 |
+
feature_html = """<section class="features" id="features">
|
| 504 |
+
<h2>Features</h2>
|
| 505 |
+
<div class="feature-grid">"""
|
| 506 |
+
|
| 507 |
+
feature_icons = {
|
| 508 |
+
"responsive": "fas fa-mobile-alt",
|
| 509 |
+
"modern": "fas fa-paint-brush",
|
| 510 |
+
"gallery": "fas fa-images",
|
| 511 |
+
"contact": "fas fa-envelope",
|
| 512 |
+
"navigation": "fas fa-compass",
|
| 513 |
+
"search": "fas fa-search",
|
| 514 |
+
"animation": "fas fa-magic",
|
| 515 |
+
"dark mode": "fas fa-moon"
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
for feature in features[:6]: # Limit to 6 features
|
| 519 |
+
icon = feature_icons.get(feature, "fas fa-star")
|
| 520 |
+
feature_html += f"""
|
| 521 |
+
<div class="feature-card">
|
| 522 |
+
<div class="feature-icon">
|
| 523 |
+
<i class="{icon}"></i>
|
| 524 |
+
</div>
|
| 525 |
+
<h3>{feature.title()}</h3>
|
| 526 |
+
<p>Experience the power of {feature} functionality in our modern website.</p>
|
| 527 |
+
</div>"""
|
| 528 |
+
|
| 529 |
+
feature_html += """
|
| 530 |
+
</div>
|
| 531 |
+
</section>"""
|
| 532 |
+
|
| 533 |
+
return feature_html
|
| 534 |
+
|
| 535 |
+
def _generate_content_sections(self, requirements: Dict) -> str:
|
| 536 |
+
"""Generate additional content sections"""
|
| 537 |
+
sections = ""
|
| 538 |
+
|
| 539 |
+
if "about" in requirements.get("features", []):
|
| 540 |
+
sections += """
|
| 541 |
+
<section class="about" id="about">
|
| 542 |
+
<div class="container">
|
| 543 |
+
<h2>About Us</h2>
|
| 544 |
+
<p>We are dedicated to creating amazing web experiences that combine beautiful design with powerful functionality.</p>
|
| 545 |
+
</div>
|
| 546 |
+
</section>"""
|
| 547 |
+
|
| 548 |
+
if "contact" in requirements.get("features", []):
|
| 549 |
+
sections += """
|
| 550 |
+
<section class="contact" id="contact">
|
| 551 |
+
<div class="container">
|
| 552 |
+
<h2>Get In Touch</h2>
|
| 553 |
+
<form class="contact-form">
|
| 554 |
+
<input type="text" placeholder="Your Name" required>
|
| 555 |
+
<input type="email" placeholder="Your Email" required>
|
| 556 |
+
<textarea placeholder="Your Message" rows="5" required></textarea>
|
| 557 |
+
<button type="submit" class="cta-button">Send Message</button>
|
| 558 |
+
</form>
|
| 559 |
+
</div>
|
| 560 |
+
</section>"""
|
| 561 |
+
|
| 562 |
+
return sections
|
| 563 |
+
|
| 564 |
+
def _generate_footer(self, requirements: Dict) -> str:
|
| 565 |
+
"""Generate footer HTML"""
|
| 566 |
+
return f"""<footer class="footer">
|
| 567 |
+
<div class="container">
|
| 568 |
+
<p>© 2024 {requirements['type'].title()}. Built with AI Website Builder.</p>
|
| 569 |
+
<div class="social-links">
|
| 570 |
+
<a href="#"><i class="fab fa-facebook"></i></a>
|
| 571 |
+
<a href="#"><i class="fab fa-twitter"></i></a>
|
| 572 |
+
<a href="#"><i class="fab fa-linkedin"></i></a>
|
| 573 |
+
<a href="#"><i class="fab fa-github"></i></a>
|
| 574 |
+
</div>
|
| 575 |
+
</div>
|
| 576 |
+
</footer>"""
|
| 577 |
+
|
| 578 |
+
def _generate_readme(self, requirements: Dict, project_name: str) -> str:
|
| 579 |
+
"""Generate README.md file"""
|
| 580 |
+
return f"""# {project_name.title()}
|
| 581 |
+
|
| 582 |
+
A modern {requirements['type']} website built with AI Website Builder.
|
| 583 |
+
|
| 584 |
+
## Features
|
| 585 |
+
|
| 586 |
+
{chr(10).join(f"- {feature.title()}" for feature in requirements.get('features', []))}
|
| 587 |
+
|
| 588 |
+
## Technologies Used
|
| 589 |
+
|
| 590 |
+
- HTML5
|
| 591 |
+
- CSS3
|
| 592 |
+
- JavaScript (ES6+)
|
| 593 |
+
- Responsive Design
|
| 594 |
+
- Font Awesome Icons
|
| 595 |
+
|
| 596 |
+
## Getting Started
|
| 597 |
+
|
| 598 |
+
1. Clone or download this project
|
| 599 |
+
2. Open `index.html` in your web browser
|
| 600 |
+
3. Or serve it with a local server:
|
| 601 |
+
python -m http.server 8000
|
| 602 |
+
|
| 603 |
+
## Customization
|
| 604 |
+
|
| 605 |
+
- Edit `styles/main.css` to modify the appearance
|
| 606 |
+
- Edit `scripts/main.js` to add functionality
|
| 607 |
+
- Edit `index.html` to modify the structure
|
| 608 |
+
|
| 609 |
+
## License
|
| 610 |
+
|
| 611 |
+
MIT License - feel free to use this project for personal or commercial purposes.
|
| 612 |
+
|
| 613 |
+
---
|
| 614 |
+
|
| 615 |
+
Built with [AI Website Builder](https://github.com/ai-website-builder)
|
| 616 |
+
"""
|
| 617 |
+
|
| 618 |
+
def _generate_package_json(self, requirements: Dict) -> str:
|
| 619 |
+
"""Generate package.json file"""
|
| 620 |
+
return json.dumps({
|
| 621 |
+
"name": "ai-generated-website",
|
| 622 |
+
"version": "1.0.0",
|
| 623 |
+
"description": f"A {requirements['type']} website built with AI",
|
| 624 |
+
"main": "index.html",
|
| 625 |
+
"scripts": {
|
| 626 |
+
"start": "python -m http.server 8000",
|
| 627 |
+
"dev": "python -m http.server 8000"
|
| 628 |
+
},
|
| 629 |
+
"keywords": ["website", "html", "css", "javascript", "ai-generated"],
|
| 630 |
+
"author": "AI Website Builder",
|
| 631 |
+
"license": "MIT"
|
| 632 |
+
}, indent=2)
|
| 633 |
+
|
| 634 |
+
def _get_color_palette(self, scheme: str) -> Dict[str, str]:
|
| 635 |
+
"""Get color palette based on scheme"""
|
| 636 |
+
palettes = {
|
| 637 |
+
"blue": {
|
| 638 |
+
"primary": "#3498db",
|
| 639 |
+
"secondary": "#2980b9",
|
| 640 |
+
"accent": "#e74c3c",
|
| 641 |
+
"text": "#2c3e50",
|
| 642 |
+
"background": "#ecf0f1",
|
| 643 |
+
"light_bg": "#ffffff"
|
| 644 |
+
},
|
| 645 |
+
"red": {
|
| 646 |
+
"primary": "#e74c3c",
|
| 647 |
+
"secondary": "#c0392b",
|
| 648 |
+
"accent": "#f39c12",
|
| 649 |
+
"text": "#2c3e50",
|
| 650 |
+
"background": "#ecf0f1",
|
| 651 |
+
"light_bg": "#ffffff"
|
| 652 |
+
},
|
| 653 |
+
"green": {
|
| 654 |
+
"primary": "#27ae60",
|
| 655 |
+
"secondary": "#229954",
|
| 656 |
+
"accent": "#f39c12",
|
| 657 |
+
"text": "#2c3e50",
|
| 658 |
+
"background": "#ecf0f1",
|
| 659 |
+
"light_bg": "#ffffff"
|
| 660 |
+
},
|
| 661 |
+
"purple": {
|
| 662 |
+
"primary": "#9b59b6",
|
| 663 |
+
"secondary": "#8e44ad",
|
| 664 |
+
"accent": "#e74c3c",
|
| 665 |
+
"text": "#2c3e50",
|
| 666 |
+
"background": "#ecf0f1",
|
| 667 |
+
"light_bg": "#ffffff"
|
| 668 |
+
},
|
| 669 |
+
"dark": {
|
| 670 |
+
"primary": "#34495e",
|
| 671 |
+
"secondary": "#2c3e50",
|
| 672 |
+
"accent": "#3498db",
|
| 673 |
+
"text": "#ecf0f1",
|
| 674 |
+
"background": "#1a1a1a",
|
| 675 |
+
"light_bg": "#2c3e50"
|
| 676 |
+
},
|
| 677 |
+
"light": {
|
| 678 |
+
"primary": "#95a5a6",
|
| 679 |
+
"secondary": "#7f8c8d",
|
| 680 |
+
"accent": "#3498db",
|
| 681 |
+
"text": "#2c3e50",
|
| 682 |
+
"background": "#ffffff",
|
| 683 |
+
"light_bg": "#ecf0f1"
|
| 684 |
+
}
|
| 685 |
+
}
|
| 686 |
+
return palettes.get(scheme, palettes["blue"])
|
| 687 |
+
|
| 688 |
+
def _load_templates(self) -> Dict:
|
| 689 |
+
"""Load website templates"""
|
| 690 |
+
return {}
|
| 691 |
+
|
| 692 |
+
def _load_components(self) -> Dict:
|
| 693 |
+
"""Load reusable components"""
|
| 694 |
+
return {}
|
| 695 |
+
|
| 696 |
+
def _generate_react_files(self, requirements: Dict) -> Dict[str, str]:
|
| 697 |
+
"""Generate React-specific files"""
|
| 698 |
+
return {
|
| 699 |
+
"src/App.js": """import React from 'react';
|
| 700 |
+
import './App.css';
|
| 701 |
+
|
| 702 |
+
function App() {
|
| 703 |
+
return (
|
| 704 |
+
<div className="App">
|
| 705 |
+
<header className="App-header">
|
| 706 |
+
<h1>React Website</h1>
|
| 707 |
+
<p>Welcome to your AI-generated React application!</p>
|
| 708 |
+
</header>
|
| 709 |
+
</div>
|
| 710 |
+
);
|
| 711 |
+
}
|
| 712 |
+
|
| 713 |
+
export default App;""",
|
| 714 |
+
"src/App.css": """.App {
|
| 715 |
+
text-align: center;
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
.App-header {
|
| 719 |
+
background-color: #282c34;
|
| 720 |
+
padding: 20px;
|
| 721 |
+
color: white;
|
| 722 |
+
min-height: 100vh;
|
| 723 |
+
display: flex;
|
| 724 |
+
flex-direction: column;
|
| 725 |
+
align-items: center;
|
| 726 |
+
justify-content: center;
|
| 727 |
+
}""",
|
| 728 |
+
"src/index.js": """import React from 'react';
|
| 729 |
+
import ReactDOM from 'react-dom';
|
| 730 |
+
import './index.css';
|
| 731 |
+
import App from './App';
|
| 732 |
+
|
| 733 |
+
ReactDOM.render(
|
| 734 |
+
<React.StrictMode>
|
| 735 |
+
<App />
|
| 736 |
+
</React.StrictMode>,
|
| 737 |
+
document.getElementById('root')
|
| 738 |
+
);""",
|
| 739 |
+
"src/index.css": """body {
|
| 740 |
+
margin: 0;
|
| 741 |
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
| 742 |
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
| 743 |
+
sans-serif;
|
| 744 |
+
}""",
|
| 745 |
+
"public/index.html": """<!DOCTYPE html>
|
| 746 |
+
<html lang="en">
|
| 747 |
+
<head>
|
| 748 |
+
<meta charset="utf-8" />
|
| 749 |
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 750 |
+
<title>React App</title>
|
| 751 |
+
</head>
|
| 752 |
+
<body>
|
| 753 |
+
<div id="root"></div>
|
| 754 |
+
</body>
|
| 755 |
+
</html>"""
|
| 756 |
+
}
|
| 757 |
+
|
| 758 |
+
def _generate_vue_files(self, requirements: Dict) -> Dict[str, str]:
|
| 759 |
+
"""Generate Vue-specific files"""
|
| 760 |
+
return {
|
| 761 |
+
"src/App.vue": """<template>
|
| 762 |
+
<div id="app">
|
| 763 |
+
<header>
|
| 764 |
+
<h1>Vue Website</h1>
|
| 765 |
+
<p>Welcome to your AI-generated Vue application!</p>
|
| 766 |
+
</header>
|
| 767 |
+
</div>
|
| 768 |
+
</template>
|
| 769 |
+
|
| 770 |
+
<script>
|
| 771 |
+
export default {
|
| 772 |
+
name: 'App'
|
| 773 |
+
}
|
| 774 |
+
</script>
|
| 775 |
+
|
| 776 |
+
<style>
|
| 777 |
+
#app {
|
| 778 |
+
font-family: Avenir, Helvetica, Arial, sans-serif;
|
| 779 |
+
text-align: center;
|
| 780 |
+
color: #2c3e50;
|
| 781 |
+
}
|
| 782 |
+
|
| 783 |
+
header {
|
| 784 |
+
background-color: #42b983;
|
| 785 |
+
color: white;
|
| 786 |
+
padding: 20px;
|
| 787 |
+
}
|
| 788 |
+
</style>""",
|
| 789 |
+
"src/main.js": """import Vue from 'vue'
|
| 790 |
+
import App from './App.vue'
|
| 791 |
+
|
| 792 |
+
new Vue({
|
| 793 |
+
render: h => h(App),
|
| 794 |
+
}).$mount('#app')""",
|
| 795 |
+
"public/index.html": """<!DOCTYPE html>
|
| 796 |
+
<html lang="en">
|
| 797 |
+
<head>
|
| 798 |
+
<meta charset="utf-8">
|
| 799 |
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
| 800 |
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
| 801 |
+
<title>Vue App</title>
|
| 802 |
+
</head>
|
| 803 |
+
<body>
|
| 804 |
+
<div id="app"></div>
|
| 805 |
+
</body>
|
| 806 |
+
</html>"""
|
| 807 |
+
}
|
| 808 |
+
|
| 809 |
+
def _generate_page(self, page: str, requirements: Dict) -> Dict[str, str]:
|
| 810 |
+
"""Generate additional pages"""
|
| 811 |
+
page_content = f"""<!DOCTYPE html>
|
| 812 |
+
<html lang="en">
|
| 813 |
+
<head>
|
| 814 |
+
<meta charset="UTF-8">
|
| 815 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 816 |
+
<title>{page.title()} - {requirements['type'].title()}</title>
|
| 817 |
+
<link rel="stylesheet" href="styles/main.css">
|
| 818 |
+
</head>
|
| 819 |
+
<body>
|
| 820 |
+
<nav class="navbar">
|
| 821 |
+
<div class="nav-container">
|
| 822 |
+
<a href="index.html" class="nav-logo">
|
| 823 |
+
<i class="fas fa-rocket"></i> {requirements['type'].title()}
|
| 824 |
+
</a>
|
| 825 |
+
<ul class="nav-menu">
|
| 826 |
+
<li><a href="index.html" class="nav-link">Home</a></li>
|
| 827 |
+
<li><a href="{page.lower()}.html" class="nav-link">{page.title()}</a></li>
|
| 828 |
+
</ul>
|
| 829 |
+
</div>
|
| 830 |
+
</nav>
|
| 831 |
+
|
| 832 |
+
<main style="margin-top: 80px; padding: 2rem;">
|
| 833 |
+
<h1>{page.title()}</h1>
|
| 834 |
+
<p>This is the {page.lower()} page of your website.</p>
|
| 835 |
+
</main>
|
| 836 |
+
|
| 837 |
+
<footer class="footer">
|
| 838 |
+
<p>© 2024 {requirements['type'].title()}. All rights reserved.</p>
|
| 839 |
+
</footer>
|
| 840 |
+
</body>
|
| 841 |
+
</html>"""
|
| 842 |
+
|
| 843 |
+
return {f"{page.lower()}.html": page_content}
|
| 844 |
+
|
| 845 |
+
def _generate_assets(self, requirements: Dict) -> Dict[str, str]:
|
| 846 |
+
"""Generate asset files"""
|
| 847 |
+
assets = {}
|
| 848 |
+
|
| 849 |
+
# Generate favicon
|
| 850 |
+
assets["favicon.ico"] = "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A"
|
| 851 |
+
|
| 852 |
+
# Generate robots.txt
|
| 853 |
+
assets["robots.txt"] = """User-agent: *
|
| 854 |
+
Allow: /
|
| 855 |
+
|
| 856 |
+
Sitemap: https://yoursite.com/sitemap.xml"""
|
| 857 |
+
|
| 858 |
+
return assets
|
requirements.txt
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0.0
|
| 2 |
+
pathlib2>=2.3.0
|
| 3 |
+
Pillow>=9.0.0
|
| 4 |
+
requests>=2.28.0
|
| 5 |
+
python-multipart>=0.0.5
|
| 6 |
+
aiofiles>=22.1.0
|
| 7 |
+
watchdog>=2.1.0
|
| 8 |
+
Jinja2>=3.1.0
|
| 9 |
+
PyYAML>=6.0
|
| 10 |
+
|
| 11 |
+
This AI Website Builder provides:
|
| 12 |
+
|
| 13 |
+
🚀 **Core Features:**
|
| 14 |
+
- Complete website generation with multiple files
|
| 15 |
+
- Powered by Qwen AI model logic
|
| 16 |
+
- Automatic live preview with hot reload
|
| 17 |
+
- Code editor with syntax highlighting
|
| 18 |
+
- Multi-file download as ZIP
|
| 19 |
+
- Project history tracking
|
| 20 |
+
|
| 21 |
+
📁 **Supported Files:**
|
| 22 |
+
- HTML, CSS, JavaScript
|
| 23 |
+
- React/Vue components
|
| 24 |
+
- JSON, Markdown, YAML
|
| 25 |
+
- Images and assets
|
| 26 |
+
- Configuration files
|
| 27 |
+
|
| 28 |
+
✨ **Advanced Features:**
|
| 29 |
+
- Multiple framework support (React, Vue, Vanilla)
|
| 30 |
+
- Responsive design generation
|
| 31 |
+
- Color scheme customization
|
| 32 |
+
- Component-based architecture
|
| 33 |
+
- SEO optimization
|
| 34 |
+
- Performance optimization
|
| 35 |
+
|
| 36 |
+
🎨 **User Interface:**
|
| 37 |
+
- Tabbed interface for different functions
|
| 38 |
+
- Real-time preview
|
| 39 |
+
- Interactive code editor
|
| 40 |
+
- Project management
|
| 41 |
+
- Settings and customization
|
| 42 |
+
|
| 43 |
+
The builder creates complete, production-ready websites with all necessary files, including HTML structure, CSS styling, JavaScript functionality, README documentation, and package configuration files. Each generated website is fully responsive and includes modern features like smooth scrolling, animations, and form validation.
|
utils.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import zipfile
|
| 4 |
+
import shutil
|
| 5 |
+
import subprocess
|
| 6 |
+
import tempfile
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import Dict, List, Optional
|
| 9 |
+
import threading
|
| 10 |
+
import time
|
| 11 |
+
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
| 12 |
+
import socket
|
| 13 |
+
|
| 14 |
+
class FileHandler:
|
| 15 |
+
"""Handle file operations for website projects"""
|
| 16 |
+
|
| 17 |
+
def __init__(self):
|
| 18 |
+
self.projects_dir = Path("projects")
|
| 19 |
+
self.projects_dir.mkdir(exist_ok=True)
|
| 20 |
+
|
| 21 |
+
def create_project(self, project_name: str, files: Dict[str, str]) -> Path:
|
| 22 |
+
"""Create a new project with generated files"""
|
| 23 |
+
project_path = self.projects_dir / project_name
|
| 24 |
+
|
| 25 |
+
# Remove existing project if it exists
|
| 26 |
+
if project_path.exists():
|
| 27 |
+
shutil.rmtree(project_path)
|
| 28 |
+
|
| 29 |
+
project_path.mkdir(exist_ok=True)
|
| 30 |
+
|
| 31 |
+
# Write all files
|
| 32 |
+
for file_path, content in files.items():
|
| 33 |
+
full_path = project_path / file_path
|
| 34 |
+
full_path.parent.mkdir(parents=True, exist_ok=True)
|
| 35 |
+
|
| 36 |
+
with open(full_path, 'w', encoding='utf-8') as f:
|
| 37 |
+
f.write(content)
|
| 38 |
+
|
| 39 |
+
return project_path
|
| 40 |
+
|
| 41 |
+
def get_project_files(self, project_path: Path) -> Dict[str, str]:
|
| 42 |
+
"""Get all files in a project"""
|
| 43 |
+
files = {}
|
| 44 |
+
if project_path.exists():
|
| 45 |
+
for file_path in project_path.rglob("*"):
|
| 46 |
+
if file_path.is_file():
|
| 47 |
+
relative_path = file_path.relative_to(project_path)
|
| 48 |
+
files[str(relative_path)] = self.get_file_content(project_path, str(relative_path))
|
| 49 |
+
return files
|
| 50 |
+
|
| 51 |
+
def get_file_content(self, project_path: Path, filename: str) -> str:
|
| 52 |
+
"""Get content of a specific file"""
|
| 53 |
+
file_path = project_path / filename
|
| 54 |
+
if file_path.exists():
|
| 55 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
| 56 |
+
return f.read()
|
| 57 |
+
return ""
|
| 58 |
+
|
| 59 |
+
def create_zip(self, project_path: Path) -> str:
|
| 60 |
+
"""Create a ZIP file of the project"""
|
| 61 |
+
zip_path = f"{project_path}.zip"
|
| 62 |
+
|
| 63 |
+
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
| 64 |
+
for file_path in project_path.rglob("*"):
|
| 65 |
+
if file_path.is_file():
|
| 66 |
+
arcname = file_path.relative_to(project_path.parent)
|
| 67 |
+
zipf.write(file_path, arcname)
|
| 68 |
+
|
| 69 |
+
return zip_path
|
| 70 |
+
|
| 71 |
+
class PreviewManager:
|
| 72 |
+
"""Manage live preview of websites"""
|
| 73 |
+
|
| 74 |
+
def __init__(self):
|
| 75 |
+
self.active_servers = {}
|
| 76 |
+
self.port_counter = 8000
|
| 77 |
+
|
| 78 |
+
def get_free_port(self) -> int:
|
| 79 |
+
"""Find a free port for the preview server"""
|
| 80 |
+
while True:
|
| 81 |
+
try:
|
| 82 |
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
| 83 |
+
s.bind(('localhost', self.port_counter))
|
| 84 |
+
return self.port_counter
|
| 85 |
+
except OSError:
|
| 86 |
+
self.port_counter += 1
|
| 87 |
+
|
| 88 |
+
def create_preview(self, project_path: Path) -> str:
|
| 89 |
+
"""Create a live preview server for the project"""
|
| 90 |
+
port = self.get_free_port()
|
| 91 |
+
|
| 92 |
+
# Start server in a separate thread
|
| 93 |
+
server_thread = threading.Thread(
|
| 94 |
+
target=self._run_server,
|
| 95 |
+
args=(project_path, port),
|
| 96 |
+
daemon=True
|
| 97 |
+
)
|
| 98 |
+
server_thread.start()
|
| 99 |
+
|
| 100 |
+
# Give server time to start
|
| 101 |
+
time.sleep(0.5)
|
| 102 |
+
|
| 103 |
+
self.active_servers[str(project_path)] = port
|
| 104 |
+
return f"http://localhost:{port}"
|
| 105 |
+
|
| 106 |
+
def update_preview(self, project_path: Path) -> str:
|
| 107 |
+
"""Update the preview (server already running)"""
|
| 108 |
+
if str(project_path) in self.active_servers:
|
| 109 |
+
port = self.active_servers[str(project_path)]
|
| 110 |
+
return f"http://localhost:{port}"
|
| 111 |
+
return self.create_preview(project_path)
|
| 112 |
+
|
| 113 |
+
def _run_server(self, project_path: Path, port: int):
|
| 114 |
+
"""Run HTTP server for preview"""
|
| 115 |
+
os.chdir(project_path)
|
| 116 |
+
|
| 117 |
+
class CustomHandler(SimpleHTTPRequestHandler):
|
| 118 |
+
def __init__(self, *args, **kwargs):
|
| 119 |
+
super().__init__(*args, directory=project_path, **kwargs)
|
| 120 |
+
|
| 121 |
+
def end_headers(self):
|
| 122 |
+
# Add CORS headers
|
| 123 |
+
self.send_header('Access-Control-Allow-Origin', '*')
|
| 124 |
+
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
|
| 125 |
+
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
| 126 |
+
super().end_headers()
|
| 127 |
+
|
| 128 |
+
try:
|
| 129 |
+
httpd = HTTPServer(('localhost', port), CustomHandler)
|
| 130 |
+
httpd.serve_forever()
|
| 131 |
+
except Exception as e:
|
| 132 |
+
print(f"Server error: {e}")
|
| 133 |
+
|
| 134 |
+
def detect_file_language(filename: str) -> str:
|
| 135 |
+
"""Detect programming language from file extension"""
|
| 136 |
+
ext = Path(filename).suffix.lower()
|
| 137 |
+
lang_map = {
|
| 138 |
+
'.html': 'html',
|
| 139 |
+
'.css': 'css',
|
| 140 |
+
'.js': 'javascript',
|
| 141 |
+
'.json': 'json',
|
| 142 |
+
'.md': 'markdown',
|
| 143 |
+
'.py': 'python',
|
| 144 |
+
'.jsx': 'jsx',
|
| 145 |
+
'.tsx': 'typescript',
|
| 146 |
+
'.ts': 'typescript',
|
| 147 |
+
'.xml': 'xml',
|
| 148 |
+
'.yaml': 'yaml',
|
| 149 |
+
'.yml': 'yaml',
|
| 150 |
+
'.sql': 'sql',
|
| 151 |
+
'.php': 'php',
|
| 152 |
+
'.rb': 'ruby',
|
| 153 |
+
'.go': 'go',
|
| 154 |
+
'.java': 'java',
|
| 155 |
+
'.c': 'c',
|
| 156 |
+
'.cpp': 'cpp',
|
| 157 |
+
'.h': 'c',
|
| 158 |
+
'.hpp': 'cpp',
|
| 159 |
+
'.scss': 'scss',
|
| 160 |
+
'.sass': 'sass',
|
| 161 |
+
'.less': 'less',
|
| 162 |
+
'.vue': 'vue',
|
| 163 |
+
'.svelte': 'svelte'
|
| 164 |
+
}
|
| 165 |
+
return lang_map.get(ext, 'text')
|
| 166 |
+
|
| 167 |
+
def format_file_size(size_bytes: int) -> str:
|
| 168 |
+
"""Format file size in human readable format"""
|
| 169 |
+
if size_bytes == 0:
|
| 170 |
+
return "0B"
|
| 171 |
+
size_names = ["B", "KB", "MB", "GB"]
|
| 172 |
+
i = 0
|
| 173 |
+
while size_bytes >= 1024 and i < len(size_names) - 1:
|
| 174 |
+
size_bytes /= 1024.0
|
| 175 |
+
i += 1
|
| 176 |
+
return f"{size_bytes:.1f}{size_names[i]}"
|