Spaces:
Sleeping
Sleeping
| import base64 | |
| import gradio as gr | |
| from huggingface_hub import InferenceClient | |
| # Free serverless models | |
| TEXT_MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct" # strong at PHP / WordPress code | |
| VISION_MODEL = "Qwen/Qwen2.5-VL-72B-Instruct" # can read screenshots | |
| client = InferenceClient() | |
| SYSTEM_PROMPT = ( | |
| "You are a senior WordPress plugin developer and web developer assistant. " | |
| "You help write, debug, and explain PHP, WordPress plugin code (hooks, filters, " | |
| "shortcodes, admin settings pages, Media Library integration), HTML, CSS, and " | |
| "JavaScript. When shown a screenshot of a website, describe the layout/section " | |
| "the user points to, then rebuild it as real HTML/CSS/PHP as closely as possible. " | |
| "Give complete, working code. When code is long, deliver it in full, installable " | |
| "form (ready to save as a .php file)." | |
| ) | |
| def image_to_data_url(img_path): | |
| with open(img_path, "rb") as f: | |
| b64 = base64.b64encode(f.read()).decode("utf-8") | |
| ext = img_path.split(".")[-1].lower() | |
| mime = "jpeg" if ext in ("jpg", "jpeg") else ext | |
| return f"data:image/{mime};base64,{b64}" | |
| def chat(message, history): | |
| # message can be a dict with "text" and "files" when multimodal input is used | |
| text = message.get("text", "") if isinstance(message, dict) else message | |
| files = message.get("files", []) if isinstance(message, dict) else [] | |
| messages = [{"role": "system", "content": SYSTEM_PROMPT}] | |
| for turn in history: | |
| if isinstance(turn, dict): | |
| role = turn.get("role") | |
| content = turn.get("content") | |
| if role and content: | |
| messages.append({"role": role, "content": content}) | |
| if files: | |
| # Vision path: send image + text together to the VL model | |
| content = [{"type": "text", "text": text or "What is in this screenshot? Rebuild the relevant section as code."}] | |
| for f in files: | |
| content.append({"type": "image_url", "image_url": {"url": image_to_data_url(f)}}) | |
| messages.append({"role": "user", "content": content}) | |
| model = VISION_MODEL | |
| else: | |
| messages.append({"role": "user", "content": text}) | |
| model = TEXT_MODEL | |
| try: | |
| response = client.chat_completion( | |
| model=model, | |
| messages=messages, | |
| max_tokens=2048, | |
| temperature=0.3, | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"⚠️ Error calling the model: {e}" | |
| demo = gr.ChatInterface( | |
| fn=chat, | |
| title="Free WordPress Dev Assistant (with screenshot support)", | |
| description=( | |
| "Free coding helper for WordPress plugins, PHP, HTML, and JS. " | |
| "Attach a screenshot and ask it to rebuild that section as code. " | |
| "Runs on Qwen2.5-Coder and Qwen2.5-VL via Hugging Face's free Inference API." | |
| ), | |
| multimodal=True, | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |