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 |
)
|