File size: 6,394 Bytes
ea305ed 9f0a84b 5080de2 ea305ed b8c5aec 21b72c8 5080de2 b8c5aec d05a045 5080de2 9f37e34 5080de2 9f0a84b 5080de2 9f37e34 5080de2 9f37e34 5080de2 9f0a84b 5080de2 c018ea8 9f37e34 5080de2 9f0a84b 9f37e34 5080de2 9f0a84b 5080de2 9f0a84b 5080de2 9f37e34 5080de2 9f37e34 b8c5aec 9f37e34 5080de2 b8c5aec 5080de2 9f0a84b 9f37e34 5080de2 9f37e34 5080de2 9f0a84b 5080de2 9f37e34 5080de2 c018ea8 5080de2 d05a045 9f37e34 5080de2 ea305ed 5080de2 aae0687 5080de2 9f37e34 1b27c48 5080de2 b8c5aec 5080de2 9f37e34 b8c5aec 9f37e34 5080de2 b8c5aec 9f37e34 b8c5aec | 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 | import os
import shutil
import subprocess
import uuid
import gradio as gr
from fastapi.staticfiles import StaticFiles
from fastapi import FastAPI
# --- Static Folder Setup ---
PREVIEW_PATH = os.path.abspath("hosted_sites")
if not os.path.exists(PREVIEW_PATH):
os.makedirs(PREVIEW_PATH)
def find_index_html(start_dir):
"""
Project mein index.html dhoondhne ke liye helper function.
Build directories ko priority milti hai.
"""
# Priority folders first
for root, dirs, files in os.walk(start_dir):
if "index.html" in files:
parts = os.path.normpath(root).split(os.sep)
if any(p in parts for p in ['dist', 'build', 'out', 'public']):
return os.path.relpath(os.path.join(root, "index.html"), PREVIEW_PATH)
# Fallback to any index.html
for root, dirs, files in os.walk(start_dir):
if "index.html" in files:
return os.path.relpath(os.path.join(root, "index.html"), PREVIEW_PATH)
return None
def run_command(cmd, cwd):
"""Real-time build logs capture karne ke liye generator function"""
process = subprocess.Popen(
cmd,
cwd=cwd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
shell=True
)
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
yield output.strip()
rc = process.poll()
if rc != 0:
raise subprocess.CalledProcessError(rc, cmd)
def deploy_project(zip_file):
if zip_file is None:
yield "β Please upload a ZIP file.", "", gr.update(visible=False), gr.update(visible=False)
return
# Unique deployment folder create karna
deploy_id = f"site-{str(uuid.uuid4())[:8]}"
deploy_dir = os.path.join(PREVIEW_PATH, deploy_id)
os.makedirs(deploy_dir)
log_accumulator = []
def log(msg):
log_accumulator.append(msg)
return "\n".join(log_accumulator)
try:
# Extract files
yield log("π¦ Extracting ZIP archive..."), "", gr.update(visible=False), gr.update(visible=False)
shutil.unpack_archive(zip_file.name, deploy_dir)
root_path = deploy_dir
is_node_project = False
# Check node project
for root, dirs, files in os.walk(deploy_dir):
if "package.json" in files:
root_path = root
is_node_project = True
break
# Build steps
if is_node_project:
yield log("π Node.js project detected."), "", gr.update(visible=False), gr.update(visible=False)
yield log("β‘ Running 'npm install'..."), "", gr.update(visible=False), gr.update(visible=False)
for line in run_command("npm install", root_path):
yield log(f"[npm] {line}"), "", gr.update(visible=False), gr.update(visible=False)
yield log("ποΈ Running 'npm run build'..."), "", gr.update(visible=False), gr.update(visible=False)
for line in run_command("npm run build", root_path):
yield log(f"[build] {line}"), "", gr.update(visible=False), gr.update(visible=False)
else:
yield log("π Static HTML project detected. Skipping build steps."), "", gr.update(visible=False), gr.update(visible=False)
# Locate preview entry-point
relative_index = find_index_html(deploy_dir)
if relative_index:
preview_url = f"/preview/{relative_index.replace(os.sep, '/')}"
success_msg = f"π **Deployment Successful!**\n\nYour site is live at: `/preview/{relative_index}`"
yield log("π Site deployed successfully!"), success_msg, gr.update(src=preview_url, visible=True), gr.update(value=f"Open App in New Tab π", link=preview_url, visible=True)
else:
yield log("β Error: 'index.html' not found."), "β Error: index.html not found.", gr.update(visible=False), gr.update(visible=False)
except subprocess.CalledProcessError as e:
yield log(f"\nβ Build Failed with exit code {e.returncode}"), "β Deployment Failed. Check console logs.", gr.update(visible=False), gr.update(visible=False)
except Exception as e:
yield log(f"\nβ Unexpected Error: {str(e)}"), "β Deployment Failed.", gr.update(visible=False), gr.update(visible=False)
# --- UI Setup ---
# Removed 'css' parameter to resolve warning in Gradio 6.0
with gr.Blocks(title="Vercel Minimal Clone") as demo:
gr.HTML("""
<div style='text-align: center; padding: 20px; border-bottom: 1px solid #eaeaea;'>
<h1 style='margin: 0; font-family: monospace;'>β² VERCEL CLONE</h1>
<p style='color: #666; margin: 5px 0 0 0;'>Instant Serverless Hosting & Preview for ZIP Deployments</p>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### π οΈ New Deployment")
zip_input = gr.File(label="Upload Project ZIP", file_types=[".zip"])
deploy_btn = gr.Button("Deploy to Production", variant="primary")
gr.Markdown("### π Build Logs (Console)")
# Fixed: Removed 'language="bash"' and used default rendering
console_output = gr.Code(label="Terminal", value="Terminal ready...", lines=12)
with gr.Column(scale=1):
gr.Markdown("### π Live Production URL")
status_text = gr.Markdown("No active deployment.")
external_link = gr.Button("Open App in New Tab π", visible=False)
preview_iframe = gr.Iframe(
label="Live Frame",
src="",
width="100%",
height="550px",
visible=False
)
deploy_btn.click(
fn=deploy_project,
inputs=zip_input,
outputs=[console_output, status_text, preview_iframe, external_link]
)
# --- FastAPI Server ---
app = FastAPI()
# Serving static preview folders
app.mount("/preview", StaticFiles(directory=PREVIEW_PATH), name="preview")
# Mounting Gradio
demo_app = gr.mount_gradio_app(app, demo, path="/")
if __name__ == "__main__":
import uvicorn
uvicorn.run(demo_app, host="0.0.0.0", port=7860) |