Ekenedirichukwu commited on
Commit
4e24d22
·
verified ·
1 Parent(s): 54b2ef4

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +76 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import gradio as gr
3
+ from huggingface_hub import InferenceClient
4
+
5
+ # Free serverless models
6
+ TEXT_MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct" # strong at PHP / WordPress code
7
+ VISION_MODEL = "Qwen/Qwen2.5-VL-72B-Instruct" # can read screenshots
8
+
9
+ client = InferenceClient()
10
+
11
+ SYSTEM_PROMPT = (
12
+ "You are a senior WordPress plugin developer and web developer assistant. "
13
+ "You help write, debug, and explain PHP, WordPress plugin code (hooks, filters, "
14
+ "shortcodes, admin settings pages, Media Library integration), HTML, CSS, and "
15
+ "JavaScript. When shown a screenshot of a website, describe the layout/section "
16
+ "the user points to, then rebuild it as real HTML/CSS/PHP as closely as possible. "
17
+ "Give complete, working code. When code is long, deliver it in full, installable "
18
+ "form (ready to save as a .php file)."
19
+ )
20
+
21
+ def image_to_data_url(img_path):
22
+ with open(img_path, "rb") as f:
23
+ b64 = base64.b64encode(f.read()).decode("utf-8")
24
+ ext = img_path.split(".")[-1].lower()
25
+ mime = "jpeg" if ext in ("jpg", "jpeg") else ext
26
+ return f"data:image/{mime};base64,{b64}"
27
+
28
+ def chat(message, history):
29
+ # message can be a dict with "text" and "files" when multimodal input is used
30
+ text = message.get("text", "") if isinstance(message, dict) else message
31
+ files = message.get("files", []) if isinstance(message, dict) else []
32
+
33
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
34
+ for turn in history:
35
+ if isinstance(turn, dict):
36
+ role = turn.get("role")
37
+ content = turn.get("content")
38
+ if role and content:
39
+ messages.append({"role": role, "content": content})
40
+
41
+ if files:
42
+ # Vision path: send image + text together to the VL model
43
+ content = [{"type": "text", "text": text or "What is in this screenshot? Rebuild the relevant section as code."}]
44
+ for f in files:
45
+ content.append({"type": "image_url", "image_url": {"url": image_to_data_url(f)}})
46
+ messages.append({"role": "user", "content": content})
47
+ model = VISION_MODEL
48
+ else:
49
+ messages.append({"role": "user", "content": text})
50
+ model = TEXT_MODEL
51
+
52
+ response = client.chat_completion(
53
+ model=model,
54
+ messages=messages,
55
+ max_tokens=2048,
56
+ temperature=0.3,
57
+ )
58
+ return response.choices[0].message.content
59
+
60
+ demo = gr.ChatInterface(
61
+ fn=chat,
62
+ title="Free WordPress Dev Assistant (with screenshot support)",
63
+ description=(
64
+ "Free coding helper for WordPress plugins, PHP, HTML, and JS. "
65
+ "Attach a screenshot and ask it to rebuild that section as code. "
66
+ "Runs on Qwen2.5-Coder and Qwen2.5-VL via Hugging Face's free Inference API."
67
+ ),
68
+ multimodal=True,
69
+ examples=[
70
+ {"text": "Write a WordPress plugin that adds a custom shortcode showing today's date.", "files": []},
71
+ {"text": "How do I add an admin settings page with a logo uploader using the Media Library?", "files": []},
72
+ ],
73
+ )
74
+
75
+ if __name__ == "__main__":
76
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio>=4.0.0
2
+ huggingface_hub>=0.24.0