Spaces:
Sleeping
Sleeping
| """ | |
| Orchestrate full repository generation by delegating to SDK-specific generators. | |
| """ | |
| from app.codegen.gradio_generator import GradioGenerator | |
| from app.codegen.docker_generator import DockerGenerator | |
| from app.codegen.readme_generator import ReadmeGenerator | |
| STATIC_TEMPLATE = """<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>{title}</title> | |
| <style> | |
| * {{ margin: 0; padding: 0; box-sizing: border-box; }} | |
| body {{ | |
| font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; | |
| background: #0f172a; | |
| color: #e2e8f0; | |
| min-height: 100vh; | |
| }} | |
| .hero {{ | |
| min-height: 60vh; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| text-align: center; | |
| padding: 2rem; | |
| background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%); | |
| }} | |
| .hero h1 {{ | |
| font-size: 3.5rem; | |
| font-weight: 800; | |
| background: linear-gradient(135deg, #38bdf8, #818cf8); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 1rem; | |
| }} | |
| .hero p {{ | |
| font-size: 1.25rem; | |
| color: #94a3b8; | |
| max-width: 600px; | |
| line-height: 1.8; | |
| }} | |
| .section {{ | |
| max-width: 1000px; | |
| margin: 0 auto; | |
| padding: 4rem 2rem; | |
| }} | |
| .section h2 {{ | |
| font-size: 2rem; | |
| margin-bottom: 2rem; | |
| color: #38bdf8; | |
| }} | |
| .grid {{ | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); | |
| gap: 1.5rem; | |
| }} | |
| .card {{ | |
| background: rgba(30, 41, 59, 0.8); | |
| border: 1px solid rgba(56, 189, 248, 0.1); | |
| border-radius: 12px; | |
| padding: 1.5rem; | |
| transition: transform 0.2s, border-color 0.2s; | |
| }} | |
| .card:hover {{ | |
| transform: translateY(-4px); | |
| border-color: rgba(56, 189, 248, 0.4); | |
| }} | |
| .card h3 {{ color: #f1f5f9; margin-bottom: 0.5rem; }} | |
| .card p {{ color: #94a3b8; line-height: 1.6; }} | |
| .skills {{ | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.75rem; | |
| }} | |
| .skill-tag {{ | |
| background: rgba(56, 189, 248, 0.15); | |
| color: #38bdf8; | |
| padding: 0.5rem 1rem; | |
| border-radius: 9999px; | |
| font-size: 0.875rem; | |
| }} | |
| .contact {{ | |
| background: rgba(30, 41, 59, 0.6); | |
| border-radius: 16px; | |
| padding: 2rem; | |
| text-align: center; | |
| }} | |
| .contact a {{ | |
| display: inline-block; | |
| margin: 0.5rem; | |
| padding: 0.75rem 1.5rem; | |
| background: linear-gradient(135deg, #38bdf8, #818cf8); | |
| color: white; | |
| text-decoration: none; | |
| border-radius: 8px; | |
| font-weight: 600; | |
| }} | |
| footer {{ | |
| text-align: center; | |
| padding: 2rem; | |
| color: #475569; | |
| font-size: 0.875rem; | |
| }} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="hero"> | |
| <h1>{title}</h1> | |
| <p>{description}</p> | |
| </div> | |
| <div class="section"> | |
| <h2>Projects</h2> | |
| <div class="grid"> | |
| <div class="card"> | |
| <h3>Project Alpha</h3> | |
| <p>A cutting-edge machine learning project that pushes the boundaries of what's possible.</p> | |
| </div> | |
| <div class="card"> | |
| <h3>Project Beta</h3> | |
| <p>An innovative data pipeline that processes millions of records in real-time.</p> | |
| </div> | |
| <div class="card"> | |
| <h3>Project Gamma</h3> | |
| <p>A beautiful visualization dashboard that makes complex data accessible.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <h2>Skills</h2> | |
| <div class="skills"> | |
| <span class="skill-tag">Python</span> | |
| <span class="skill-tag">Machine Learning</span> | |
| <span class="skill-tag">Deep Learning</span> | |
| <span class="skill-tag">NLP</span> | |
| <span class="skill-tag">Computer Vision</span> | |
| <span class="skill-tag">Data Science</span> | |
| <span class="skill-tag">FastAPI</span> | |
| <span class="skill-tag">Docker</span> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="contact"> | |
| <h2>Get in Touch</h2> | |
| <p style="color: #94a3b8; margin: 1rem 0;">Interested in collaborating? Reach out!</p> | |
| <a href="mailto:hello@example.com">Email</a> | |
| <a href="https://github.com">GitHub</a> | |
| <a href="https://linkedin.com">LinkedIn</a> | |
| </div> | |
| </div> | |
| <footer> | |
| <p>Built with care. Hosted on Hugging Face Spaces.</p> | |
| </footer> | |
| </body> | |
| </html> | |
| """ | |
| class RepoGenerator: | |
| """Orchestrate full repo generation for any SDK type.""" | |
| def __init__(self): | |
| self.gradio_gen = GradioGenerator() | |
| self.docker_gen = DockerGenerator() | |
| self.readme_gen = ReadmeGenerator() | |
| def generate(self, plan: dict, prompt: str) -> dict: | |
| """ | |
| Generate all files for a complete HF Space repo. | |
| Returns dict of {filepath: content}. | |
| """ | |
| sdk = plan.get("sdk", "gradio") | |
| if sdk == "gradio": | |
| return self._generate_gradio_repo(plan, prompt) | |
| elif sdk == "docker": | |
| return self._generate_docker_repo(plan, prompt) | |
| else: | |
| return self._generate_static_repo(plan, prompt) | |
| def _generate_gradio_repo(self, plan: dict, prompt: str) -> dict: | |
| """Generate a complete Gradio Space repo.""" | |
| files = {} | |
| # README.md | |
| files["README.md"] = self.readme_gen.generate(plan, "gradio") | |
| # app.py - the main Gradio application | |
| files["app.py"] = self.gradio_gen.generate(plan, prompt) | |
| # requirements.txt | |
| files["requirements.txt"] = self._gradio_requirements(plan) | |
| # .gitignore | |
| files[".gitignore"] = self._gitignore() | |
| return files | |
| def _generate_docker_repo(self, plan: dict, prompt: str) -> dict: | |
| """Generate a complete Docker Space repo.""" | |
| # Get docker-specific files from the generator | |
| docker_files = self.docker_gen.generate(plan, prompt) | |
| files = {} | |
| # README.md (always generate our own) | |
| files["README.md"] = self.readme_gen.generate(plan, "docker") | |
| # Merge docker-generated files | |
| for name, content in docker_files.items(): | |
| files[name] = content | |
| # .gitignore | |
| files[".gitignore"] = self._gitignore() | |
| return files | |
| def _generate_static_repo(self, plan: dict, prompt: str) -> dict: | |
| """Generate a complete Static Space repo.""" | |
| title = plan.get("title", "My Site") | |
| description = plan.get("description", "A static website") | |
| files = {} | |
| # README.md | |
| files["README.md"] = self.readme_gen.generate(plan, "static") | |
| # index.html | |
| files["index.html"] = STATIC_TEMPLATE.format( | |
| title=title, | |
| description=description, | |
| ) | |
| # style.css (additional styles) | |
| files["style.css"] = """/* Additional custom styles */ | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'); | |
| body { | |
| font-family: 'Inter', system-ui, sans-serif; | |
| } | |
| /* Smooth scrolling */ | |
| html { | |
| scroll-behavior: smooth; | |
| } | |
| /* Animated gradient background */ | |
| @keyframes gradient-shift { | |
| 0% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| 100% { background-position: 0% 50%; } | |
| } | |
| .hero { | |
| background-size: 200% 200%; | |
| animation: gradient-shift 8s ease infinite; | |
| } | |
| /* Fade-in animation */ | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .card { | |
| animation: fadeInUp 0.5s ease forwards; | |
| } | |
| """ | |
| files[".gitignore"] = self._gitignore() | |
| return files | |
| def _gradio_requirements(self, plan: dict) -> str: | |
| """Generate requirements.txt for Gradio apps.""" | |
| deps = [ | |
| "gradio>=5.9.1", | |
| "huggingface-hub>=0.27.1", | |
| ] | |
| # Add task-specific dependencies | |
| task = plan.get("model_task", "") | |
| if task in ("text-to-image", "image-classification", "object-detection"): | |
| deps.append("Pillow>=10.0.0") | |
| if "chart_output" in plan.get("components", []): | |
| deps.append("matplotlib>=3.8.0") | |
| deps.append("numpy>=1.26.0") | |
| return "\n".join(deps) + "\n" | |
| def _gitignore(self) -> str: | |
| return """__pycache__/ | |
| *.py[cod] | |
| *$py.class | |
| *.egg-info/ | |
| dist/ | |
| build/ | |
| .env | |
| .venv/ | |
| venv/ | |
| .DS_Store | |
| *.log | |
| """ | |
| def edit(self, plan: dict, current_files: dict, edit_prompt: str) -> dict: | |
| """Edit an existing repo based on user instructions.""" | |
| sdk = plan.get("sdk", "gradio") | |
| updated = dict(current_files) | |
| if sdk == "gradio" and "app.py" in current_files: | |
| updated["app.py"] = self.gradio_gen.edit(plan, current_files["app.py"], edit_prompt) | |
| elif sdk == "docker": | |
| docker_updated = self.docker_gen.edit(plan, current_files, edit_prompt) | |
| updated.update(docker_updated) | |
| # Static sites: for now return unchanged (could add LLM-based HTML editing) | |
| return updated | |