Spaces:
Running
Running
add import github and HF model support
Browse files
app.py
CHANGED
@@ -3437,6 +3437,270 @@ def load_project_from_url(url: str) -> Tuple[str, str]:
|
|
3437 |
|
3438 |
return f"β
Successfully imported project from {username}/{project_name}", code_content
|
3439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3440 |
# Gradio Theme Configurations with proper theme objects
|
3441 |
def get_saved_theme():
|
3442 |
"""Get the saved theme preference from file"""
|
@@ -3736,18 +4000,16 @@ with gr.Blocks(
|
|
3736 |
apply_theme_btn = gr.Button("Apply Theme", variant="primary", size="sm")
|
3737 |
theme_status = gr.Markdown("")
|
3738 |
|
3739 |
-
#
|
3740 |
-
gr.Markdown("π₯
|
3741 |
load_project_url = gr.Textbox(
|
3742 |
-
label="
|
3743 |
-
placeholder="https://huggingface.co/spaces/
|
3744 |
lines=1
|
3745 |
)
|
3746 |
load_project_btn = gr.Button("Import Project", variant="secondary", size="sm")
|
3747 |
load_project_status = gr.Markdown(visible=False)
|
3748 |
|
3749 |
-
gr.Markdown("---")
|
3750 |
-
|
3751 |
input = gr.Textbox(
|
3752 |
label="What would you like to build?",
|
3753 |
placeholder="Describe your application...",
|
@@ -3901,6 +4163,7 @@ with gr.Blocks(
|
|
3901 |
)
|
3902 |
with gr.Tab("Preview"):
|
3903 |
sandbox = gr.HTML(label="Live preview")
|
|
|
3904 |
# History tab hidden per user request
|
3905 |
# with gr.Tab("History"):
|
3906 |
# history_output = gr.Chatbot(show_label=False, height=400, type="messages")
|
@@ -3908,58 +4171,74 @@ with gr.Blocks(
|
|
3908 |
# Keep history_output as hidden component to maintain functionality
|
3909 |
history_output = gr.Chatbot(show_label=False, height=400, type="messages", visible=False)
|
3910 |
|
3911 |
-
#
|
3912 |
-
def
|
3913 |
if not url.strip():
|
3914 |
-
return gr.update(value="Please enter a URL.", visible=True)
|
3915 |
-
|
3916 |
-
|
3917 |
-
|
3918 |
-
|
3919 |
# Extract space info for deployment
|
3920 |
is_valid, username, project_name = check_hf_space_url(url)
|
3921 |
space_info = f"{username}/{project_name}" if is_valid else ""
|
3922 |
-
|
3923 |
-
#
|
3924 |
-
|
3925 |
-
loaded_history = [[f"Loaded project from {url}", code]]
|
3926 |
-
# Determine preview based on content (HTML or Streamlit)
|
3927 |
-
if code and (code.strip().startswith('<!DOCTYPE html>') or code.strip().startswith('<html')):
|
3928 |
-
preview_html = send_to_sandbox(code)
|
3929 |
-
code_lang = "html"
|
3930 |
-
elif is_streamlit_code(code):
|
3931 |
-
preview_html = send_streamlit_to_stlite(code)
|
3932 |
-
code_lang = "python"
|
3933 |
-
elif is_gradio_code(code):
|
3934 |
-
preview_html = send_gradio_to_lite(code)
|
3935 |
-
code_lang = "python"
|
3936 |
-
else:
|
3937 |
-
preview_html = "<div style='padding:1em;color:#888;text-align:center;'>Preview not available for this file type.</div>"
|
3938 |
-
code_lang = "html"
|
3939 |
-
|
3940 |
return [
|
3941 |
gr.update(value=status, visible=True),
|
3942 |
gr.update(value=code, language=code_lang),
|
3943 |
-
gr.update(value=
|
3944 |
gr.update(value=""),
|
3945 |
loaded_history,
|
3946 |
history_to_chatbot_messages(loaded_history),
|
3947 |
-
gr.update(value=space_info, visible=True),
|
3948 |
-
gr.update(value="Update Existing Space", visible=True)
|
3949 |
]
|
3950 |
else:
|
3951 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3952 |
return [
|
3953 |
gr.update(value=status, visible=True),
|
3954 |
-
gr.update(),
|
3955 |
-
gr.update(),
|
3956 |
-
gr.update(),
|
3957 |
-
|
3958 |
-
|
3959 |
gr.update(value="", visible=False),
|
3960 |
gr.update(value="π Deploy App", visible=False)
|
3961 |
]
|
3962 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3963 |
# Event handlers
|
3964 |
def update_code_language(language):
|
3965 |
return gr.update(language=get_gradio_language(language))
|
@@ -4035,9 +4314,9 @@ with gr.Blocks(
|
|
4035 |
# No imported project found, return no changes
|
4036 |
return [gr.update(), gr.update()]
|
4037 |
|
4038 |
-
#
|
4039 |
load_project_btn.click(
|
4040 |
-
|
4041 |
inputs=[load_project_url],
|
4042 |
outputs=[load_project_status, code_output, sandbox, load_project_url, history, history_output, space_name_input, deploy_btn]
|
4043 |
)
|
|
|
3437 |
|
3438 |
return f"β
Successfully imported project from {username}/{project_name}", code_content
|
3439 |
|
3440 |
+
# -------- Repo/Model Import (GitHub & Hugging Face model) --------
|
3441 |
+
def _parse_repo_or_model_url(url: str) -> Tuple[str, Optional[dict]]:
|
3442 |
+
"""Parse a URL and detect if it's a GitHub repo, HF Space, or HF Model.
|
3443 |
+
|
3444 |
+
Returns a tuple of (kind, meta) where kind in {"github", "hf_space", "hf_model", "unknown"}
|
3445 |
+
Meta contains parsed identifiers.
|
3446 |
+
"""
|
3447 |
+
try:
|
3448 |
+
parsed = urlparse(url.strip())
|
3449 |
+
netloc = (parsed.netloc or "").lower()
|
3450 |
+
path = (parsed.path or "").strip("/")
|
3451 |
+
# Hugging Face spaces
|
3452 |
+
if ("huggingface.co" in netloc or netloc.endswith("hf.co")) and path.startswith("spaces/"):
|
3453 |
+
parts = path.split("/")
|
3454 |
+
if len(parts) >= 3:
|
3455 |
+
return "hf_space", {"username": parts[1], "project": parts[2]}
|
3456 |
+
# Hugging Face model repo (default)
|
3457 |
+
if ("huggingface.co" in netloc or netloc.endswith("hf.co")) and not path.startswith(("spaces/", "datasets/", "organizations/")):
|
3458 |
+
parts = path.split("/")
|
3459 |
+
if len(parts) >= 2:
|
3460 |
+
repo_id = f"{parts[0]}/{parts[1]}"
|
3461 |
+
return "hf_model", {"repo_id": repo_id}
|
3462 |
+
# GitHub repo
|
3463 |
+
if "github.com" in netloc:
|
3464 |
+
parts = path.split("/")
|
3465 |
+
if len(parts) >= 2:
|
3466 |
+
return "github", {"owner": parts[0], "repo": parts[1]}
|
3467 |
+
except Exception:
|
3468 |
+
pass
|
3469 |
+
return "unknown", None
|
3470 |
+
|
3471 |
+
def _fetch_hf_model_readme(repo_id: str) -> Optional[str]:
|
3472 |
+
"""Fetch README.md (model card) for a Hugging Face model repo."""
|
3473 |
+
try:
|
3474 |
+
api = HfApi()
|
3475 |
+
# Try direct README.md first
|
3476 |
+
try:
|
3477 |
+
local_path = api.hf_hub_download(repo_id=repo_id, filename="README.md", repo_type="model")
|
3478 |
+
with open(local_path, "r", encoding="utf-8") as f:
|
3479 |
+
return f.read()
|
3480 |
+
except Exception:
|
3481 |
+
# Some repos use README at root without explicit type
|
3482 |
+
local_path = api.hf_hub_download(repo_id=repo_id, filename="README.md")
|
3483 |
+
with open(local_path, "r", encoding="utf-8") as f:
|
3484 |
+
return f.read()
|
3485 |
+
except Exception:
|
3486 |
+
return None
|
3487 |
+
|
3488 |
+
def _fetch_github_readme(owner: str, repo: str) -> Optional[str]:
|
3489 |
+
"""Fetch README.md from a GitHub repo via raw URLs, trying HEAD/main/master."""
|
3490 |
+
bases = [
|
3491 |
+
f"https://raw.githubusercontent.com/{owner}/{repo}/HEAD/README.md",
|
3492 |
+
f"https://raw.githubusercontent.com/{owner}/{repo}/main/README.md",
|
3493 |
+
f"https://raw.githubusercontent.com/{owner}/{repo}/master/README.md",
|
3494 |
+
]
|
3495 |
+
for url in bases:
|
3496 |
+
try:
|
3497 |
+
resp = requests.get(url, timeout=10)
|
3498 |
+
if resp.status_code == 200 and resp.text:
|
3499 |
+
return resp.text
|
3500 |
+
except Exception:
|
3501 |
+
continue
|
3502 |
+
return None
|
3503 |
+
|
3504 |
+
def _extract_transformers_or_diffusers_snippet(markdown_text: str) -> Tuple[Optional[str], Optional[str]]:
|
3505 |
+
"""Extract the most relevant Python code block referencing transformers/diffusers from markdown.
|
3506 |
+
|
3507 |
+
Returns (language, code). If not found, returns (None, None).
|
3508 |
+
"""
|
3509 |
+
if not markdown_text:
|
3510 |
+
return None, None
|
3511 |
+
# Find fenced code blocks
|
3512 |
+
code_blocks = []
|
3513 |
+
import re as _re
|
3514 |
+
for match in _re.finditer(r"```([\w+-]+)?\s*\n([\s\S]*?)```", markdown_text, _re.IGNORECASE):
|
3515 |
+
lang = (match.group(1) or "").lower()
|
3516 |
+
code = match.group(2) or ""
|
3517 |
+
code_blocks.append((lang, code.strip()))
|
3518 |
+
# Filter for transformers/diffusers relevance
|
3519 |
+
def score_block(code: str) -> int:
|
3520 |
+
score = 0
|
3521 |
+
kws = [
|
3522 |
+
"from transformers", "import transformers", "pipeline(",
|
3523 |
+
"AutoModel", "AutoTokenizer", "text-generation",
|
3524 |
+
"from diffusers", "import diffusers", "DiffusionPipeline",
|
3525 |
+
"StableDiffusion", "UNet", "EulerDiscreteScheduler"
|
3526 |
+
]
|
3527 |
+
for kw in kws:
|
3528 |
+
if kw in code:
|
3529 |
+
score += 1
|
3530 |
+
# Prefer longer, self-contained snippets
|
3531 |
+
score += min(len(code) // 200, 5)
|
3532 |
+
return score
|
3533 |
+
scored = sorted(
|
3534 |
+
[cb for cb in code_blocks if any(kw in cb[1] for kw in ["transformers", "diffusers", "pipeline(", "StableDiffusion"])],
|
3535 |
+
key=lambda x: score_block(x[1]),
|
3536 |
+
reverse=True,
|
3537 |
+
)
|
3538 |
+
if scored:
|
3539 |
+
return scored[0][0] or None, scored[0][1]
|
3540 |
+
return None, None
|
3541 |
+
|
3542 |
+
def _infer_task_from_context(snippet: Optional[str], pipeline_tag: Optional[str]) -> str:
|
3543 |
+
"""Infer a task string for transformers pipeline; fall back to provided pipeline_tag or 'text-generation'."""
|
3544 |
+
if pipeline_tag:
|
3545 |
+
return pipeline_tag
|
3546 |
+
if not snippet:
|
3547 |
+
return "text-generation"
|
3548 |
+
lowered = snippet.lower()
|
3549 |
+
task_hints = {
|
3550 |
+
"text-generation": ["text-generation", "automodelforcausallm"],
|
3551 |
+
"text2text-generation": ["text2text-generation", "t5forconditionalgeneration"],
|
3552 |
+
"fill-mask": ["fill-mask", "automodelformaskedlm"],
|
3553 |
+
"summarization": ["summarization"],
|
3554 |
+
"translation": ["translation"],
|
3555 |
+
"text-classification": ["text-classification", "sequenceclassification"],
|
3556 |
+
"automatic-speech-recognition": ["speechrecognition", "automatic-speech-recognition", "asr"],
|
3557 |
+
"image-classification": ["image-classification"],
|
3558 |
+
"zero-shot-image-classification": ["zero-shot-image-classification"],
|
3559 |
+
}
|
3560 |
+
for task, hints in task_hints.items():
|
3561 |
+
if any(h in lowered for h in hints):
|
3562 |
+
return task
|
3563 |
+
# Inspect explicit pipeline("task")
|
3564 |
+
import re as _re
|
3565 |
+
m = _re.search(r"pipeline\(\s*['\"]([\w\-]+)['\"]", snippet)
|
3566 |
+
if m:
|
3567 |
+
return m.group(1)
|
3568 |
+
return "text-generation"
|
3569 |
+
|
3570 |
+
def _generate_gradio_app_from_transformers(repo_id: str, task: str) -> str:
|
3571 |
+
"""Build a minimal Gradio app using transformers.pipeline for a given model and task."""
|
3572 |
+
# Map simple UI per task; default to text in/out
|
3573 |
+
if task in {"text-generation", "text2text-generation", "summarization", "translation", "fill-mask"}:
|
3574 |
+
return (
|
3575 |
+
"import gradio as gr\n"
|
3576 |
+
"from transformers import pipeline\n\n"
|
3577 |
+
f"pipe = pipeline(task='{task}', model='{repo_id}')\n\n"
|
3578 |
+
"def infer(prompt, max_new_tokens=256, temperature=0.7, top_p=0.95):\n"
|
3579 |
+
" if '\u2047' in prompt:\n"
|
3580 |
+
" # Fill-mask often uses [MASK]; keep generic handling\n"
|
3581 |
+
" pass\n"
|
3582 |
+
" out = pipe(prompt, max_new_tokens=max_new_tokens, do_sample=True, temperature=temperature, top_p=top_p)\n"
|
3583 |
+
" if isinstance(out, list):\n"
|
3584 |
+
" if isinstance(out[0], dict):\n"
|
3585 |
+
" return next(iter(out[0].values())) if out[0] else str(out)\n"
|
3586 |
+
" return str(out[0])\n"
|
3587 |
+
" return str(out)\n\n"
|
3588 |
+
"demo = gr.Interface(\n"
|
3589 |
+
" fn=infer,\n"
|
3590 |
+
" inputs=[gr.Textbox(label='Input', lines=8), gr.Slider(1, 2048, value=256, label='max_new_tokens'), gr.Slider(0.0, 1.5, value=0.7, step=0.01, label='temperature'), gr.Slider(0.0, 1.0, value=0.95, step=0.01, label='top_p')],\n"
|
3591 |
+
" outputs=gr.Textbox(label='Output', lines=8),\n"
|
3592 |
+
" title='Transformers Demo'\n"
|
3593 |
+
")\n\n"
|
3594 |
+
"if __name__ == '__main__':\n"
|
3595 |
+
" demo.launch()\n"
|
3596 |
+
)
|
3597 |
+
elif task in {"text-classification"}:
|
3598 |
+
return (
|
3599 |
+
"import gradio as gr\n"
|
3600 |
+
"from transformers import pipeline\n\n"
|
3601 |
+
f"pipe = pipeline(task='{task}', model='{repo_id}')\n\n"
|
3602 |
+
"def infer(text):\n"
|
3603 |
+
" out = pipe(text)\n"
|
3604 |
+
" # Expect list of dicts with label/score\n"
|
3605 |
+
" return {o['label']: float(o['score']) for o in out}\n\n"
|
3606 |
+
"demo = gr.Interface(fn=infer, inputs=gr.Textbox(lines=6), outputs=gr.Label(), title='Text Classification')\n\n"
|
3607 |
+
"if __name__ == '__main__':\n"
|
3608 |
+
" demo.launch()\n"
|
3609 |
+
)
|
3610 |
+
else:
|
3611 |
+
# Fallback generic text pipeline (pipeline infers task from model config)
|
3612 |
+
return (
|
3613 |
+
"import gradio as gr\n"
|
3614 |
+
"from transformers import pipeline\n\n"
|
3615 |
+
f"pipe = pipeline(model='{repo_id}')\n\n"
|
3616 |
+
"def infer(prompt):\n"
|
3617 |
+
" out = pipe(prompt)\n"
|
3618 |
+
" if isinstance(out, list):\n"
|
3619 |
+
" if isinstance(out[0], dict):\n"
|
3620 |
+
" return next(iter(out[0].values())) if out[0] else str(out)\n"
|
3621 |
+
" return str(out[0])\n"
|
3622 |
+
" return str(out)\n\n"
|
3623 |
+
"demo = gr.Interface(fn=infer, inputs=gr.Textbox(lines=8), outputs=gr.Textbox(lines=8), title='Transformers Demo')\n\n"
|
3624 |
+
"if __name__ == '__main__':\n"
|
3625 |
+
" demo.launch()\n"
|
3626 |
+
)
|
3627 |
+
|
3628 |
+
def _generate_gradio_app_from_diffusers(repo_id: str) -> str:
|
3629 |
+
"""Build a minimal Gradio app for text-to-image using diffusers."""
|
3630 |
+
return (
|
3631 |
+
"import gradio as gr\n"
|
3632 |
+
"import torch\n"
|
3633 |
+
"from diffusers import DiffusionPipeline\n\n"
|
3634 |
+
f"pipe = DiffusionPipeline.from_pretrained('{repo_id}')\n"
|
3635 |
+
"device = 'cuda' if torch.cuda.is_available() else 'cpu'\n"
|
3636 |
+
"pipe = pipe.to(device)\n\n"
|
3637 |
+
"def infer(prompt, guidance_scale=7.0, num_inference_steps=30, seed=0):\n"
|
3638 |
+
" generator = None if seed == 0 else torch.Generator(device=device).manual_seed(int(seed))\n"
|
3639 |
+
" image = pipe(prompt, guidance_scale=float(guidance_scale), num_inference_steps=int(num_inference_steps), generator=generator).images[0]\n"
|
3640 |
+
" return image\n\n"
|
3641 |
+
"demo = gr.Interface(\n"
|
3642 |
+
" fn=infer,\n"
|
3643 |
+
" inputs=[gr.Textbox(label='Prompt'), gr.Slider(0.0, 15.0, value=7.0, step=0.1, label='guidance_scale'), gr.Slider(1, 100, value=30, step=1, label='num_inference_steps'), gr.Slider(0, 2**32-1, value=0, step=1, label='seed')],\n"
|
3644 |
+
" outputs=gr.Image(type='pil'),\n"
|
3645 |
+
" title='Diffusers Text-to-Image'\n"
|
3646 |
+
")\n\n"
|
3647 |
+
"if __name__ == '__main__':\n"
|
3648 |
+
" demo.launch()\n"
|
3649 |
+
)
|
3650 |
+
|
3651 |
+
def _generate_streamlit_wrapper(gradio_code: str) -> str:
|
3652 |
+
"""Convert a simple Gradio app into a Streamlit wrapper by embedding via components if needed.
|
3653 |
+
If code is already Streamlit, return as is. Otherwise, provide a basic Streamlit UI calling the same pipeline.
|
3654 |
+
"""
|
3655 |
+
# For now, simply return a minimal placeholder to keep scope tight; prefer Gradio by default.
|
3656 |
+
return (
|
3657 |
+
"import streamlit as st\n"
|
3658 |
+
"st.markdown('This model is best used with a Gradio app in this tool. Switch framework to Gradio for a runnable demo.')\n"
|
3659 |
+
)
|
3660 |
+
|
3661 |
+
def import_repo_to_app(url: str, framework: str = "Gradio") -> Tuple[str, str, str]:
|
3662 |
+
"""Import a GitHub or HF model repo and return the raw code snippet from README/model card.
|
3663 |
+
|
3664 |
+
Returns (status_markdown, code_snippet, preview_html). Preview left empty; UI will decide.
|
3665 |
+
"""
|
3666 |
+
if not url or not url.strip():
|
3667 |
+
return "Please enter a repository URL.", "", ""
|
3668 |
+
kind, meta = _parse_repo_or_model_url(url)
|
3669 |
+
if kind == "hf_space" and meta:
|
3670 |
+
# Spaces already contain runnable apps; keep existing behavior to fetch main file raw
|
3671 |
+
status, code = load_project_from_url(url)
|
3672 |
+
return status, code, ""
|
3673 |
+
# Fetch markdown
|
3674 |
+
markdown = None
|
3675 |
+
repo_id = None
|
3676 |
+
pipeline_tag = None
|
3677 |
+
library_name = None
|
3678 |
+
if kind == "hf_model" and meta:
|
3679 |
+
repo_id = meta.get("repo_id")
|
3680 |
+
# Try model info to get pipeline tag/library
|
3681 |
+
try:
|
3682 |
+
api = HfApi()
|
3683 |
+
info = api.model_info(repo_id)
|
3684 |
+
pipeline_tag = getattr(info, "pipeline_tag", None)
|
3685 |
+
library_name = getattr(info, "library_name", None)
|
3686 |
+
except Exception:
|
3687 |
+
pass
|
3688 |
+
markdown = _fetch_hf_model_readme(repo_id)
|
3689 |
+
elif kind == "github" and meta:
|
3690 |
+
markdown = _fetch_github_readme(meta.get("owner"), meta.get("repo"))
|
3691 |
+
else:
|
3692 |
+
return "Error: Unsupported or invalid URL. Provide a GitHub repo or Hugging Face model URL.", "", ""
|
3693 |
+
|
3694 |
+
if not markdown:
|
3695 |
+
return "Error: Could not fetch README/model card.", "", ""
|
3696 |
+
|
3697 |
+
lang, snippet = _extract_transformers_or_diffusers_snippet(markdown)
|
3698 |
+
if not snippet:
|
3699 |
+
return "Error: No relevant transformers/diffusers code block found in README/model card.", "", ""
|
3700 |
+
|
3701 |
+
status = "β
Imported code snippet from README/model card. Use it as a starting point."
|
3702 |
+
return status, snippet, ""
|
3703 |
+
|
3704 |
# Gradio Theme Configurations with proper theme objects
|
3705 |
def get_saved_theme():
|
3706 |
"""Get the saved theme preference from file"""
|
|
|
4000 |
apply_theme_btn = gr.Button("Apply Theme", variant="primary", size="sm")
|
4001 |
theme_status = gr.Markdown("")
|
4002 |
|
4003 |
+
# Unified Import section
|
4004 |
+
gr.Markdown("π₯ Import Project (Space, GitHub, or Model)")
|
4005 |
load_project_url = gr.Textbox(
|
4006 |
+
label="Project URL",
|
4007 |
+
placeholder="https://huggingface.co/spaces/user/space OR https://huggingface.co/user/model OR https://github.com/owner/repo",
|
4008 |
lines=1
|
4009 |
)
|
4010 |
load_project_btn = gr.Button("Import Project", variant="secondary", size="sm")
|
4011 |
load_project_status = gr.Markdown(visible=False)
|
4012 |
|
|
|
|
|
4013 |
input = gr.Textbox(
|
4014 |
label="What would you like to build?",
|
4015 |
placeholder="Describe your application...",
|
|
|
4163 |
)
|
4164 |
with gr.Tab("Preview"):
|
4165 |
sandbox = gr.HTML(label="Live preview")
|
4166 |
+
# Removed Import Logs tab for cleaner UI
|
4167 |
# History tab hidden per user request
|
4168 |
# with gr.Tab("History"):
|
4169 |
# history_output = gr.Chatbot(show_label=False, height=400, type="messages")
|
|
|
4171 |
# Keep history_output as hidden component to maintain functionality
|
4172 |
history_output = gr.Chatbot(show_label=False, height=400, type="messages", visible=False)
|
4173 |
|
4174 |
+
# Unified import handler
|
4175 |
+
def handle_import_project(url):
|
4176 |
if not url.strip():
|
4177 |
+
return [gr.update(value="Please enter a URL.", visible=True), gr.update(), gr.update(), gr.update(), [], [], gr.update(value="", visible=False), gr.update(value="π Deploy App", visible=False)]
|
4178 |
+
|
4179 |
+
kind, meta = _parse_repo_or_model_url(url)
|
4180 |
+
if kind == "hf_space":
|
4181 |
+
status, code = load_project_from_url(url)
|
4182 |
# Extract space info for deployment
|
4183 |
is_valid, username, project_name = check_hf_space_url(url)
|
4184 |
space_info = f"{username}/{project_name}" if is_valid else ""
|
4185 |
+
loaded_history = [[f"Imported Space from {url}", code]]
|
4186 |
+
# Preview not auto-rendered for imported content
|
4187 |
+
code_lang = "python" if (is_streamlit_code(code) or is_gradio_code(code)) else "html"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4188 |
return [
|
4189 |
gr.update(value=status, visible=True),
|
4190 |
gr.update(value=code, language=code_lang),
|
4191 |
+
gr.update(value=""),
|
4192 |
gr.update(value=""),
|
4193 |
loaded_history,
|
4194 |
history_to_chatbot_messages(loaded_history),
|
4195 |
+
gr.update(value=space_info, visible=True),
|
4196 |
+
gr.update(value="Update Existing Space", visible=True)
|
4197 |
]
|
4198 |
else:
|
4199 |
+
# GitHub or HF model β return raw snippet for LLM starting point
|
4200 |
+
status, code, _ = import_repo_to_app(url)
|
4201 |
+
loaded_history = [[f"Imported Repo/Model from {url}", code]]
|
4202 |
+
code_lang = "python"
|
4203 |
+
lower = (code or "").lower()
|
4204 |
+
if code.strip().startswith("<!doctype html>") or code.strip().startswith("<html"):
|
4205 |
+
code_lang = "html"
|
4206 |
+
elif "```json" in lower:
|
4207 |
+
code_lang = "json"
|
4208 |
return [
|
4209 |
gr.update(value=status, visible=True),
|
4210 |
+
gr.update(value=code, language=code_lang),
|
4211 |
+
gr.update(value=""),
|
4212 |
+
gr.update(value=""),
|
4213 |
+
loaded_history,
|
4214 |
+
history_to_chatbot_messages(loaded_history),
|
4215 |
gr.update(value="", visible=False),
|
4216 |
gr.update(value="π Deploy App", visible=False)
|
4217 |
]
|
4218 |
|
4219 |
+
# Import repo/model handler
|
4220 |
+
def handle_import_repo(url, framework):
|
4221 |
+
status, code, preview = import_repo_to_app(url, framework)
|
4222 |
+
# Heuristically set editor language based on snippet fencing or content
|
4223 |
+
code_lang = "python"
|
4224 |
+
lowered = (code or "").lower()
|
4225 |
+
if code.strip().startswith("<!doctype html>") or code.strip().startswith("<html"):
|
4226 |
+
code_lang = "html"
|
4227 |
+
elif "import gradio" in lowered or "from gradio" in lowered:
|
4228 |
+
code_lang = "python"
|
4229 |
+
elif "streamlit as st" in lowered or "import streamlit" in lowered:
|
4230 |
+
code_lang = "python"
|
4231 |
+
elif "from transformers" in lowered or "import transformers" in lowered:
|
4232 |
+
code_lang = "python"
|
4233 |
+
elif "from diffusers" in lowered or "import diffusers" in lowered:
|
4234 |
+
code_lang = "python"
|
4235 |
+
return [
|
4236 |
+
gr.update(value=status, visible=True),
|
4237 |
+
gr.update(value=code, language=code_lang),
|
4238 |
+
gr.update(value=""),
|
4239 |
+
gr.update(value=f"URL: {url}\n\n{status}"),
|
4240 |
+
]
|
4241 |
+
|
4242 |
# Event handlers
|
4243 |
def update_code_language(language):
|
4244 |
return gr.update(language=get_gradio_language(language))
|
|
|
4314 |
# No imported project found, return no changes
|
4315 |
return [gr.update(), gr.update()]
|
4316 |
|
4317 |
+
# Unified import event
|
4318 |
load_project_btn.click(
|
4319 |
+
handle_import_project,
|
4320 |
inputs=[load_project_url],
|
4321 |
outputs=[load_project_status, code_output, sandbox, load_project_url, history, history_output, space_name_input, deploy_btn]
|
4322 |
)
|