File size: 13,921 Bytes
74cee4d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | # פרויקט Python מלא: מחולל אתרי אינטרנט AI אוטומטי להרצה ב-Hugging Face Spaces (Gradio)
# גרסה: 1.0
# תואם בדיוק לדרישות: מודל AI, Gradio, עורך קוד, תצוגה מקדימה, ניהול פרויקטים, מספר דפים, יצוא ZIP
# הסבר: הקוד משתמש ב-InferenceClient (huggingface_hub) למודל Qwen2.5-Coder-1.5B-Instruct – קל ומהיר ב-Spaces ללא צורך ב-GPU כבד.
# כל הקבצים נשמרים בזיכרון (State), תומך בעריכה, תצוגה מקדימה עם inline CSS/JS, ושמירה/טעינה כ-JSON + ZIP.
# הערות מפורטות בכל חלק – כפי שביקשת.
import gradio as gr
from huggingface_hub import InferenceClient
import json
import zipfile
import io
import re
# ====================== 1. מודל AI חזק (Code Generation) ======================
# מודל Hugging Face מתאים במיוחד ליצירת HTML/CSS/JS איכותי ומוכן להרצה
client = InferenceClient(model="Qwen/Qwen2.5-Coder-1.5B-Instruct")
def generate_website(description: str, primary_color: str, design_style: str, page_names_str: str):
"""
יוצר את כל הקבצים באמצעות מודל AI.
הפרומפט באנגלית (מודלים לקוד טובים יותר באנגלית) אבל התוצאה מותאמת לעברית/עיצוב.
"""
page_names = [p.strip() for p in page_names_str.split(",") if p.strip()]
if not page_names:
page_names = ["index"]
prompt = f"""You are an expert full-stack web developer. Create a complete, beautiful, responsive multi-page website.
Description: {description}
Primary color: {primary_color}
Design style: {design_style} (use Tailwind CSS via CDN + custom CSS)
Pages: {', '.join(page_names)}
Requirements:
- Use HTML5, Tailwind CSS CDN, modern design.
- Each HTML file must contain: <link rel="stylesheet" href="style.css"> and <script src="script.js"></script>
- Add nice navigation between pages.
- Include some JavaScript interactivity (buttons, smooth scroll, mobile menu).
- Make it production-ready and beautiful.
Return ONLY a valid JSON object (no extra text):
{{
"files": {{
"style.css": "FULL CSS CODE HERE",
"script.js": "FULL JS CODE HERE",
"index.html": "FULL HTML CODE HERE",
"about.html": "FULL HTML CODE HERE",
... (one file for each page)
}}
}}
"""
try:
response = client.text_generation(
prompt=prompt,
max_new_tokens=8192,
temperature=0.6,
top_p=0.9,
do_sample=True
)
# ניקוי אם המודל הוסיף markdown
response = response.strip()
if response.startswith("```json"):
response = response[7:]
if response.endswith("```"):
response = response[:-3]
data = json.loads(response)
files = data.get("files", {})
# בדיקת בטיחות – תמיד קיימים קבצים בסיסיים
if "style.css" not in files:
files["style.css"] = f"body {{ color: {primary_color}; font-family: system-ui; }}"
if "script.js" not in files:
files["script.js"] = "// JS interactivity\nconsole.log('Site loaded!');"
return files, "✅ האתר נוצר בהצלחה! ערוך, צפה והורד."
except Exception as e:
return {}, f"❌ שגיאה: {str(e)}\nנסה תיאור יותר מפורט או לחץ שוב."
# ====================== 2. הכנת תצוגה מקדימה (iframe-like עם inline) ======================
def prepare_preview_html(files: dict, page_name: str):
"""הופך את הדף ל-single HTML עם CSS + JS inline כדי שיעבוד בתוך Gradio."""
if not files or page_name not in files:
return "<h1 style='text-align:center;padding:50px;'>בחר דף להצגה</h1>"
html = files[page_name]
css = files.get("style.css", "")
js = files.get("script.js", "")
# הסרת קישורים חיצוניים (כדי שהכל יהיה inline)
html = re.sub(r'<link[^>]*href=["\']style\.css["\'][^>]*>', '', html, flags=re.IGNORECASE)
html = re.sub(r'<script[^>]*src=["\']script\.js["\'][^>]*></script>', '', html, flags=re.IGNORECASE)
# הוספת inline CSS
if re.search(r'</head>', html, re.IGNORECASE):
html = re.sub(r'(?i)</head>', f'<style>\n{css}\n</style></head>', html)
else:
html = f'<head><style>\n{css}\n</style></head>\n{html}'
# הוספת inline JS
if re.search(r'</body>', html, re.IGNORECASE):
html = re.sub(r'(?i)</body>', f'<script>\n{js}\n</script></body>', html)
else:
html += f'\n<script>\n{js}\n</script>'
return html
# ====================== 3. יצוא ZIP ======================
def create_zip_download(files: dict):
"""יוצר ZIP בזיכרון עם כל הקבצים הנפרדים."""
if not files:
return None
buffer = io.BytesIO()
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zf:
for filename, content in files.items():
zf.writestr(filename, content.encode("utf-8"))
buffer.seek(0)
return buffer.getvalue()
# ====================== 4. שמירה וטעינה של פרויקט (JSON) ======================
def save_project_json(files: dict):
if not files:
return None
return json.dumps(files, ensure_ascii=False, indent=2).encode("utf-8")
def load_project(uploaded_file):
"""טוען פרויקט JSON שהמשתמש העלה."""
if uploaded_file is None:
return {}, "לא נבחר קובץ"
try:
content = uploaded_file.decode("utf-8")
files = json.loads(content)
return files, "✅ פרויקט נטען בהצלחה!"
except Exception as e:
return {}, f"❌ שגיאה בטעינה: {str(e)}"
# ====================== 5. פונקציות עזר לעורך ======================
def update_editor(selected_file, current_files):
"""מעדכן את עורך הקוד לפי הקובץ שנבחר."""
if not current_files or selected_file not in current_files:
return "// אין קובץ", "javascript"
ext = selected_file.split(".")[-1].lower()
lang = "html" if ext == "html" else "css" if ext == "css" else "javascript"
return current_files[selected_file], lang
def save_edited_code(selected_file, new_code, current_files):
"""שומר שינויים מהעורך."""
if selected_file and current_files:
current_files[selected_file] = new_code
return current_files, "✅ שינויים נשמרו!", create_zip_download(current_files), save_project_json(current_files)
return current_files, "❌ לא נשמר", None, None
# ====================== 6. ממשק Gradio מלא ======================
with gr.Blocks(title="מחולל אתרי AI – Gradio", theme=gr.themes.Soft()) as iface:
gr.Markdown("# 🛠️ מחולל אתרי אינטרנט אוטומטי עם AI\n"
"תאר → בחר צבע וסגנון → יצור → ערוך → צפה → הורד ZIP\n"
"תומך ב-Landing Page, Blog, Portfolio, Dashboard ועוד!")
files_state = gr.State({}) # שומר את כל הקבצים בזיכרון
with gr.Tab("✨ יצירת אתר חדש"):
with gr.Row():
with gr.Column(scale=2):
description_input = gr.Textbox(
label="📝 תיאור האתר",
placeholder="אתר Landing Page לחנות בגדים אופנתית עם דף מוצרים, בלוג וטופס יצירת קשר...",
lines=4
)
primary_color_input = gr.ColorPicker(label="🎨 צבע עיקרי", value="#2563eb")
design_style_input = gr.Dropdown(
choices=["מודרני", "מינימליסטי", "כהה", "תוסס", "תאגידי", "פורטפוליו"],
label="🎨 סגנון עיצוב",
value="מודרני"
)
page_names_input = gr.Textbox(
label="📄 שמות הדפים (מופרדים בפסיקים)",
value="index,about,services,contact",
placeholder="index,blog,portfolio"
)
generate_button = gr.Button("🚀 יצור אתר!", variant="primary", size="large")
with gr.Column(scale=1):
status_output = gr.Textbox(label="סטטוס", interactive=False, value="מוכן ליצירה...")
gr.Markdown("### 👀 תצוגה מקדימה + עורך קוד")
with gr.Row():
with gr.Column(scale=1):
preview_page_dropdown = gr.Dropdown(label="בחר דף להצגה", choices=[], interactive=True)
live_preview = gr.HTML(
value="<div style='text-align:center;padding:80px;background:#f8fafc;border-radius:12px;'>התצוגה המקדימה תופיע כאן</div>",
label="תצוגה מקדימה (מתעדכנת אוטומטית)"
)
refresh_preview_btn = gr.Button("🔄 רענן תצוגה")
with gr.Column(scale=1):
file_dropdown = gr.Dropdown(label="בחר קובץ לעריכה", choices=[], interactive=True)
code_editor = gr.Code(
label="עורך קוד (HTML / CSS / JS)",
language="html",
lines=22,
interactive=True
)
save_edit_button = gr.Button("💾 שמור שינויים בקוד")
with gr.Tab("📁 ניהול פרויקטים & יצוא"):
gr.Markdown("### שמור / טען פרויקטים")
with gr.Row():
upload_project = gr.File(label="העלה פרויקט JSON קודם", file_types=[".json"], type="binary")
load_status = gr.Textbox(label="סטטוס טעינה", interactive=False)
with gr.Row():
save_json_button = gr.DownloadButton(label="💾 שמור פרויקט כ-JSON", value=None, visible=False)
download_zip_button = gr.DownloadButton(label="📦 הורד אתר מלא כ-ZIP", value=None, visible=False)
# ====================== אירועים (Events) ======================
generate_button.click(
fn=lambda desc, color, style, pages, state: (
*generate_website(desc, color, style, pages),
# outputs: files, status, file_dropdown, preview_page_dropdown, live_preview, zip_bytes, json_bytes
),
inputs=[description_input, primary_color_input, design_style_input, page_names_input, files_state],
outputs=[
files_state,
status_output,
file_dropdown,
preview_page_dropdown,
live_preview,
download_zip_button,
save_json_button
]
)
# עדכון עורך קוד
file_dropdown.change(
fn=update_editor,
inputs=[file_dropdown, files_state],
outputs=[code_editor]
)
# שמירת עריכה + עדכון כפתורי הורדה
save_edit_button.click(
fn=save_edited_code,
inputs=[file_dropdown, code_editor, files_state],
outputs=[files_state, status_output, download_zip_button, save_json_button]
)
# רענון תצוגה מקדימה
def refresh_preview(page, state):
return prepare_preview_html(state, page)
preview_page_dropdown.change(
fn=refresh_preview,
inputs=[preview_page_dropdown, files_state],
outputs=[live_preview]
)
refresh_preview_btn.click(
fn=refresh_preview,
inputs=[preview_page_dropdown, files_state],
outputs=[live_preview]
)
# טעינת פרויקט JSON
def handle_upload(uploaded, state):
new_files, msg = load_project(uploaded)
if new_files:
html_pages = [f for f in new_files if f.endswith(".html")]
all_files = list(new_files.keys())
return (
new_files,
msg,
gr.Dropdown(choices=all_files, value=all_files[0] if all_files else None),
gr.Dropdown(choices=html_pages, value=html_pages[0] if html_pages else None),
prepare_preview_html(new_files, html_pages[0] if html_pages else ""),
create_zip_download(new_files),
save_project_json(new_files)
)
return state, msg, gr.Dropdown(), gr.Dropdown(), live_preview.value, None, None
upload_project.upload(
fn=handle_upload,
inputs=[upload_project, files_state],
outputs=[
files_state,
load_status,
file_dropdown,
preview_page_dropdown,
live_preview,
download_zip_button,
save_json_button
]
)
gr.Markdown("---\n"
"**טיפים:**\n"
"• התצוגה המקדימה מראה דף אחד בכל פעם (קישורים לא עובדים כי אין שרת). הורד ZIP כדי לראות את כל האתר.\n"
"• אחרי עריכה – לחץ \"שמור שינויים\" ואז \"רענן תצוגה\".\n"
"• כל הפרויקטים נשמרים רק בדפדפן – הורד JSON כדי לשמור.")
# ====================== 7. הרצה ======================
if __name__ == "__main__":
iface.launch(
server_name="0.0.0.0",
server_port=7860,
share=False, # ב-Spaces זה אוטומטי
debug=True
) |