Download app.py from nhkr/AA: direct link, hf CLI and curl.
- Browser
- Download file 13.9 kB
-
https://huggingface.co/spaces/nhkr/AA/resolve/main/app.py
- Command line
-
hf download hf://spaces/nhkr/AA/app.py
-
curl -L -o app.py https://huggingface.co/spaces/nhkr/AA/resolve/main/app.py
13.9 kB
| # פרויקט 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 | |
| ) |