Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import requests, json, os, time | |
| from fastapi import FastAPI, Request | |
| from fastapi.responses import JSONResponse | |
| import uvicorn | |
| OLLAMA = "http://localhost:11434" | |
| MODEL = "FableForge-AI/shellwhisperer" | |
| fastapi_app = FastAPI(docs_url=None, redoc_url=None) | |
| async def api_chat(request: Request): | |
| body = await request.json() | |
| try: | |
| r = requests.post(f"{OLLAMA}/api/chat", json=body, timeout=120) | |
| return JSONResponse(content=r.json()) | |
| except Exception as e: | |
| return JSONResponse(status_code=500, content={"error": str(e)}) | |
| # ββ helpers ββ | |
| def model_info(): | |
| """Get model details and status.""" | |
| info = { | |
| "ready": False, | |
| "model": MODEL, | |
| "size": "?", | |
| "speed": "?", | |
| "error": "", | |
| } | |
| try: | |
| r = requests.get(f"{OLLAMA}/api/tags", timeout=5) | |
| if r.status_code == 200: | |
| models = r.json().get("models", []) | |
| for m in models: | |
| if MODEL in m.get("name", ""): | |
| info["ready"] = True | |
| size_gb = m.get("size", 0) / 1e9 | |
| info["size"] = f"{size_gb:.1f} GB" | |
| break | |
| if not info["ready"]: | |
| info["error"] = "Model not pulled yet" | |
| else: | |
| info["error"] = f"Ollama returned {r.status_code}" | |
| except requests.ConnectionError: | |
| info["error"] = "Ollama not running" | |
| except Exception as e: | |
| info["error"] = str(e) | |
| return info | |
| def generate(prompt, temp): | |
| if not prompt.strip(): | |
| yield "β οΈ Enter a prompt first." | |
| return | |
| info = model_info() | |
| if not info["ready"]: | |
| yield f"β³ Model loading... ({info['error']})" | |
| return | |
| try: | |
| r = requests.post(f"{OLLAMA}/api/chat", json={ | |
| "model": MODEL, | |
| "messages": [ | |
| {"role": "system", "content": "You are ShellWhisperer-1.5B, a shell and CLI specialist. Output working code only, no explanations."}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| "stream": True, | |
| "options": {"temperature": temp, "num_ctx": 16384} | |
| }, stream=True, timeout=120) | |
| full = [] | |
| for line in r.iter_lines(): | |
| if not line: | |
| continue | |
| try: | |
| d = json.loads(line) | |
| chunk = d.get("message", {}).get("content", "") | |
| if chunk: | |
| full.append(chunk) | |
| yield "".join(full) | |
| except json.JSONDecodeError: | |
| pass | |
| if not full: | |
| yield "β οΈ Empty response from model. Try again." | |
| except requests.Timeout: | |
| yield "β° Request timed out after 120s. Try a shorter prompt." | |
| except Exception as e: | |
| yield f"β Error: {e}" | |
| # ββ UI ββ | |
| with gr.Blocks( | |
| title="ShellWhisperer-1.5B Β· API", | |
| theme=gr.themes.Soft(), | |
| fill_height=True, | |
| css="""footer { display: none !important; } | |
| .status-ok { color: #22c55e; font-weight: 600; } | |
| .status-loading { color: #f59e0b; font-weight: 600; } | |
| .status-err { color: #ef4444; font-weight: 600; } | |
| .api-box { background: #1f2937; color: #e5e7eb; padding: 1em; border-radius: 8px; font-family: monospace; font-size: 0.9em; overflow-x: auto; } | |
| """, | |
| ) as demo: | |
| gr.Markdown("""# π ShellWhisperer-1.5B Β· API Demo | |
| **CLI & Shell Code Specialist** Β· 1 GB Β· 29 tok/s Β· 16K context Β· Apache 2.0 | |
| Built by **FableForge AI** β part of the [Mythos model ecosystem](https://github.com/KingLabsA/mythos). | |
| """) | |
| # ββ status dashboard ββ | |
| with gr.Row(): | |
| status_badge = gr.Markdown("β³ Checking...") | |
| model_size = gr.Markdown("") | |
| model_speed = gr.Markdown("") | |
| with gr.Tabs(): | |
| with gr.TabItem("π§ͺ Try it"): | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| inp = gr.Textbox( | |
| label="Prompt", | |
| placeholder="Write a bash script to...", | |
| lines=4, | |
| ) | |
| with gr.Row(): | |
| temp = gr.Slider(0.0, 1.0, value=0.3, step=0.05, label="Temperature") | |
| btn = gr.Button("π Generate", variant="primary", scale=1, size="lg") | |
| out = gr.Textbox(label="Output", lines=16) | |
| gr.Markdown("### π‘ Try these") | |
| gr.Examples( | |
| examples=[ | |
| ["Write a bash script to monitor a directory for new files and log them"], | |
| ["Write a Python script to batch resize images to 800px wide"], | |
| ["Write a Docker Compose file for a web app with PostgreSQL"], | |
| ["Write a git pre-commit hook that runs tests"], | |
| ], | |
| inputs=inp, | |
| label="", | |
| ) | |
| with gr.TabItem("π‘ API"): | |
| gr.Markdown("""### REST API | |
| This space exposes a standard Ollama-compatible chat endpoint. | |
| ``` | |
| POST /api/chat | |
| Content-Type: application/json | |
| ``` | |
| **cURL:** | |
| ```bash | |
| curl -X POST https://karma-devops-shellwhisperer-demo.hf.space/api/chat \\ | |
| -H "Content-Type: application/json" \\ | |
| -d '{ | |
| "model": "FableForge-AI/shellwhisperer", | |
| "messages": [{"role": "user", "content": "Write a bash script"}], | |
| "stream": false, | |
| "options": {"temperature": 0.3, "num_ctx": 16384} | |
| }' | |
| ``` | |
| **Python:** | |
| ```python | |
| import requests | |
| r = requests.post("https://karma-devops-shellwhisperer-demo.hf.space/api/chat", json={ | |
| "model": "FableForge-AI/shellwhisperer", | |
| "messages": [{"role": "user", "content": "Write a bash script"}], | |
| "stream": False, | |
| "options": {"temperature": 0.3, "num_ctx": 16384} | |
| }) | |
| print(r.json()["message"]["content"]) | |
| ``` | |
| """) | |
| with gr.TabItem("βΉοΈ About"): | |
| gr.Markdown("""### Model | |
| | Property | Value | | |
| |---|---| | |
| | Name | ShellWhisperer-1.5B | | |
| | Author | FableForge AI ([KingLabsA](https://github.com/KingLabsA)) | | |
| | Size | 1 GB | | |
| | Speed | ~29 tok/s (T4 GPU) | | |
| | Context | 16,384 tokens | | |
| | License | Apache 2.0 | | |
| | Base | Qwen2.5-Coder-1.5B-Instruct | | |
| ### Links | |
| - [GitHub: KingLabsA/mythos](https://github.com/KingLabsA/mythos) | |
| - [HuggingFace: King3Djbl](https://huggingface.co/King3Djbl) | |
| - [HuggingFace: fableforge-ai](https://huggingface.co/fableforge-ai) | |
| - [Ollama: FableForge-AI](https://ollama.com/FableForge-AI) | |
| """) | |
| # ββ events ββ | |
| def refresh_status(): | |
| info = model_info() | |
| if info["ready"]: | |
| badge = f'<span class="status-ok">β Model: Ready</span>' | |
| size = f'<span class="status-ok">π¦ {info["size"]}</span>' | |
| speed = '<span class="status-ok">β‘ ~29 tok/s</span>' | |
| else: | |
| badge = f'<span class="status-loading">β³ Model: {info["error"]}</span>' | |
| size = "" | |
| speed = "" | |
| return badge, size, speed | |
| demo.load(fn=refresh_status, outputs=[status_badge, model_size, model_speed]) | |
| gr.Timer(30).tick(fn=refresh_status, outputs=[status_badge, model_size, model_speed]) | |
| btn.click( | |
| fn=generate, | |
| inputs=[inp, temp], | |
| outputs=out, | |
| ) | |
| app = gr.mount_gradio_app(fastapi_app, demo, path="/") | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |