acecalisto3 commited on
Commit
a5e32bb
Β·
verified Β·
1 Parent(s): 69352c0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -258
app.py CHANGED
@@ -1,271 +1,154 @@
 
 
1
  import gradio as gr
2
- from transformers import AutoModelForCausalLM, AutoTokenizer, GenerationConfig
3
- import torch
4
- import logging
5
- from typing import List, Dict, Any
6
- from functools import partial
7
 
8
- # Configure logging
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
 
12
- class VibeThinker:
13
- def __init__(self, model_path: str = "WeiboAI/VibeThinker-1.5B"):
14
- self.model_path = model_path
15
- logger.info(f"Loading model {model_path}...")
16
-
17
- try:
18
- # Use trust_remote_code only if absolutely required (VibeThinker needs it)
19
- self.tokenizer = AutoTokenizer.from_pretrained(
20
- model_path,
21
- trust_remote_code=True,
22
- padding_side="left" # Important for generation
23
- )
24
-
25
- # Add pad token if missing (common with some custom models)
26
- if self.tokenizer.pad_token is None:
27
- self.tokenizer.pad_token = self.tokenizer.eos_token
28
- self.tokenizer.pad_token_id = self.tokenizer.eos_token_id
29
-
30
- self.model = AutoModelForCausalLM.from_pretrained(
31
- model_path,
32
- torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32,
33
- device_map="auto",
34
- low_cpu_mem_usage=True,
35
- trust_remote_code=True,
36
- )
37
-
38
- self.model.eval()
39
- logger.info("Model loaded successfully.")
40
-
41
- except Exception as e:
42
- logger.error(f"Failed to load model: {e}")
43
- raise
44
 
45
- def infer_text(self, messages: List[Dict[str, str]], **gen_kwargs) -> str:
46
- try:
47
- # Apply chat template safely
48
- text = self.tokenizer.apply_chat_template(
49
- messages,
50
- tokenize=False,
51
- add_generation_prompt=True
52
- )
53
-
54
- inputs = self.tokenizer(
55
- text,
56
- return_tensors="pt",
57
- truncation=True,
58
- max_length=8192 # Prevent OOM on very long histories
59
- ).to(self.model.device)
60
-
61
- # Default generation config (tuned for quality + coherence)
62
- default_gen = {
63
- "max_new_tokens": 2048,
64
- "do_sample": True,
65
- "temperature": 0.7,
66
- "top_p": 0.90,
67
- "top_k": 50,
68
- "repetition_penalty": 1.1,
69
- "eos_token_id": self.tokenizer.eos_token_id,
70
- "pad_token_id": self.tokenizer.pad_token_id,
71
- }
72
- default_gen.update(gen_kwargs)
73
-
74
- with torch.no_grad():
75
- generated_ids = self.model.generate(
76
- **inputs,
77
- generation_config=GenerationConfig(**default_gen)
78
- )
79
-
80
- # Decode only the newly generated part
81
- response_ids = generated_ids[0][inputs.input_ids.shape[-1]:]
82
- response = self.tokenizer.decode(response_ids, skip_special_tokens=True).strip()
83
-
84
- return response
85
-
86
- except torch.cuda.OutOfMemoryError:
87
- torch.cuda.empty_cache()
88
- return "❌ GPU ran out of memory. Please shorten your conversation history or try again."
89
- except Exception as e:
90
- logger.error(f"Generation error: {e}")
91
- return f"❌ An error occurred during generation: {str(e)}"
92
-
93
-
94
- # === Initialize model once (global) ===
95
- try:
96
- model = VibeThinker()
97
- except Exception:
98
- model = None
99
- error_msg = "Failed to load VibeThinker model. The app will run in fallback mode."
100
- logger.error(error_msg)
101
-
102
- # === System prompt (clear, focused, and optimized for Joomla/Yootheme) ===
103
- SYSTEM_PROMPT = """
104
- You are an expert Joomla developer specializing in YOOtheme Pro Builder (dynamic content, custom elements, layout library).
105
- Your task is to convert or optimize any provided HTML/CSS/JS into clean, high-performance code that works perfectly inside YOOtheme Pro elements (HTML, Custom Element, Code element, etc.).
106
-
107
- Rules:
108
- - Always use inline styles or scoped CSS when needed (no external files unless requested).
109
- - Prefer YOOtheme dynamic tags {{ }} when relevant.
110
- - Ensure responsive design (use uk-grid, uk-width-*, flex, etc.).
111
- - Optimize for performance: minify when possible, avoid heavy frameworks.
112
- - Wrap JavaScript in <script> tags with defer if needed.
113
- - Output ONLY the final optimized code unless the user asks for explanation.
114
- - If the input is already good, enhance it (accessibility, speed, modern syntax).
115
- """
116
-
117
- def build_messages(history: List[List[Any]], user_message: str) -> List[Dict[str, str]]:
118
- messages = [{"role": "system", "content": SYSTEM_PROMPT}]
119
-
120
- for human, assistant in history:
121
- if human:
122
- messages.append({"role": "user", "content": human})
123
- if assistant:
124
- messages.append({"role": "assistant", "content": assistant})
125
-
126
- messages.append({"role": "user", "content": user_message})
127
- return messages
128
-
129
- def chatbot_response(message: str, history: List[List[str]]) -> str:
130
- if model is None:
131
- return "🚨 Model failed to load. Please check server logs."
132
-
133
- messages = build_messages(history, message)
134
-
135
- # Stream the response using Gradio's streaming
136
- for chunk in stream_response(messages):
137
- yield chunk
138
-
139
- def stream_response(messages: List[Dict[str, str]]):
140
- if model is None:
141
- yield "Model not available."
142
- return
143
 
 
 
 
144
  try:
145
- text = model.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
146
- inputs = model.tokenizer(text, return_tensors="pt").to(model.model.device)
147
-
148
- streamer = partial(model.model.generate,
149
- **inputs,
150
- streamer=None, # We'll do manual streaming for better control
151
- max_new_tokens=2048,
152
- do_sample=True,
153
- temperature=0.7,
154
- top_p=0.90,
155
- repetition_penalty=1.1,
156
- pad_token_id=model.tokenizer.pad_token_id)
157
-
158
- generated_text = ""
159
- for new_token in streamer:
160
- # This is a simplified streaming approach; for real token-by-token streaming use TextIteratorStreamer
161
- pass # Replace with real streaming if needed (see below for full streaming version)
162
-
163
- # Simpler: just return full response (still fast with bfloat16)
164
- response = model.infer_text(messages)
165
- yield response
166
-
167
  except Exception as e:
168
- yield f"Error: {str(e)}"
169
-
170
-
171
- # === Proper streaming version (recommended) ===
172
- from transformers import TextIteratorStreamer
173
- import threading
174
-
175
- def chatbot_response_stream(message: str, history: List[List[str]]):
176
- if model is None:
177
- yield "🚨 Model failed to load."
178
- return
179
-
180
- messages = build_messages(history, message)
181
- text = model.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
182
- inputs = model.tokenizer(text, return_tensors="pt").to(model.model.device)
183
 
184
- streamer = TextIteratorStreamer(model.tokenizer, skip_prompt=True, skip_special_tokens=True)
185
-
186
- generation_kwargs = {
187
- "inputs": inputs.input_ids,
188
- "streamer": streamer,
189
- "max_new_tokens": 2048,
190
- "do_sample": True,
191
- "temperature": 0.7,
192
- "top_p": 0.90,
193
- "top_k": 50,
194
- "repetition_penalty": 1.1,
195
- "pad_token_id": model.tokenizer.pad_token_id,
196
- }
197
-
198
- thread = threading.Thread(target=model.model.generate, kwargs=generation_kwargs)
199
- thread.start()
200
-
201
- generated_text = ""
202
- for new_text in streamer:
203
- generated_text += new_text
204
- yield generated_text
205
-
206
- # === Gradio Interface ===
207
- with gr.Blocks(
208
- theme=gr.themes.Soft(),
209
- title="Joomla YOOtheme Pro Optimizer",
210
- css="""
211
- .gradio-container {max-width: 1000px !important; margin: auto;}
212
- footer {display: none !important;}
213
  """
214
- ) as demo:
215
- gr.Markdown(
216
- """
217
- # πŸš€ Joomla YOOtheme Pro Optimizer
218
- Powered by **WeiboAI/VibeThinker-1.5B** βˆ™ Real-time streaming βˆ™ Optimized for YOOtheme Builder
219
- [Built with ❀️ using Anycoder](https://huggingface.co/spaces/akhaliq/anycoder) |
220
- [Model](https://huggingface.co/WeiboAI/VibeThinker-1.5B) βˆ™
221
- [Report issues](https://github.com/your-repo)
222
- """
223
- )
224
 
225
- chat = gr.ChatInterface(
226
- fn=chatbot_response_stream,
227
- chatbot=gr.Chatbot(
228
- height=600,
229
- show_copy_button=True,
230
- avatar_images=(
231
- "https://em-content.zobj.net/source/twitter/53/robot_1f916.png",
232
- "https://yootheme.com/site/templates/yootheme/images/yootheme/logo.svg"
233
- ),
234
- render_markdown=True
235
- ),
236
- textbox=gr.Textbox(
237
- placeholder="Paste your HTML/CSS/JS here and ask to optimize for YOOtheme Pro Builder...",
238
- container=False,
239
- scale=7,
240
- autofocus=True
241
- ),
242
- examples=[
243
- ["Make this Bootstrap card work perfectly in YOOtheme Pro as a custom element"],
244
- ["Convert this Tailwind section to pure UIKit + YOOtheme dynamic content"],
245
- ["Optimize this heavy JS animation for YOOtheme Code element (no jQuery)"],
246
- ],
247
- cache_examples=False,
248
- retry_btn="πŸ”„ Retry",
249
- undo_btn="β†Ά Undo",
250
- clear_btn="πŸ—‘οΈ Clear Chat",
251
- submit_btn="Optimize β†’"
252
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
- gr.Markdown(
255
- """
256
- ### Tips:
257
- - Paste raw HTML, full pages, or just snippets
258
- - Ask for dynamic content (`{{ article.title }}`, etc.)
259
- - Request minification, accessibility improvements, or UIKit conversion
260
- - Streaming responses appear in real-time
261
- """
262
- )
263
 
264
  if __name__ == "__main__":
265
- demo.queue(max_size=20).launch(
266
- server_name="0.0.0.0",
267
- server_port=7860,
268
- share=False, # Set to True if you want public link
269
- favicon_path="https://yootheme.com/site/templates/yootheme/images/favicon.ico",
270
- allowed_paths=[] # Add static files if needed
271
- )
 
1
+ import os
2
+ import time
3
  import gradio as gr
4
+ from playwright.sync_api import sync_playwright
5
+ from huggingface_hub import InferenceClient, login
 
 
 
6
 
7
+ # --- AUTHENTICATION ---
8
+ # Ensure this token has WRITE permissions
9
+ HF_TOKEN = os.environ.get("HF_TOKEN")
10
 
11
+ # --- AGENT BRAIN & IMAGINATION ---
12
+ # We use Qwen-2.5-Coder for logic (Smartest open coder) and FLUX for images.
13
+ LLM_MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct"
14
+ IMG_MODEL = "black-forest-labs/FLUX.1-dev"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ client = InferenceClient(token=HF_TOKEN)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ def generate_image_asset(prompt):
19
+ """Generates an image using FLUX based on the context."""
20
+ print(f"🎨 Generative Cortex: Creating image for '{prompt}'...")
21
  try:
22
+ # Enhance prompt for better aesthetics
23
+ enhanced_prompt = f"professional web design asset, high quality, {prompt}, 8k resolution, trending on artstation"
24
+ image = client.text_to_image(enhanced_prompt, model=IMG_MODEL)
25
+ return image, f"Generated: {prompt}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  except Exception as e:
27
+ return None, f"Image Gen Error: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ def interpret_task(task_description):
30
+ """
31
+ Uses the LLM to translate a human request into a Joomla/YooTheme strategy.
32
+ Returns a structured list of steps (pseudo-code for the bot).
33
+ """
34
+ system_prompt = """
35
+ You are an expert Joomla 5 and YooTheme Pro Automator.
36
+ Convert the user's natural language request into a logical step-by-step execution plan for a Playwright bot.
37
+ The bot can: login, goto_url, click_selector, type_text, upload_image.
38
+ Identify if an image needs to be generated based on the text.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  """
40
+
41
+ try:
42
+ messages = [
43
+ {"role": "system", "content": system_prompt},
44
+ {"role": "user", "content": f"Task: {task_description}"}
45
+ ]
46
+ response = client.chat_completion(messages, model=LLM_MODEL, max_tokens=500)
47
+ return response.choices[0].message.content
48
+ except Exception as e:
49
+ return f"Brain Error: {e}"
50
 
51
+ def execute_mission(joomla_url, username, password, task_input, dry_run):
52
+ logs = []
53
+ generated_assets = []
54
+
55
+ def log(msg):
56
+ t = time.strftime("%H:%M:%S")
57
+ entry = f"[{t}] {msg}"
58
+ logs.append(entry)
59
+ print(entry)
60
+ return "\n".join(logs)
61
+
62
+ log(f"πŸš€ Hub-Enhancer Agent Initiated.")
63
+ log(f"🧠 Analyzing Request via {LLM_MODEL}...")
64
+
65
+ # 1. Ask the LLM what to do
66
+ strategy = interpret_task(task_input)
67
+ log(f"πŸ“‹ Strategy Formulated:\n{strategy[:200]}...") # Log first 200 chars of strategy
68
+
69
+ # 2. Check for Image Generation Triggers
70
+ if "image" in task_input.lower() or "photo" in task_input.lower() or "banner" in task_input.lower():
71
+ log("🎨 Visual Requirement Detected. Initializing Generative Pipeline...")
72
+ # Extract a prompt (simplified logic here, usually LLM does this)
73
+ img_prompt = task_input.replace("generate", "").replace("create", "").strip()
74
+ img, status = generate_image_asset(img_prompt)
75
+ if img:
76
+ generated_assets.append((img, "Auto-Generated Asset"))
77
+ log("βœ… Asset Created successfully.")
78
+
79
+ # 3. Execute Browser Actions
80
+ if dry_run:
81
+ log("⚠️ DRY RUN: Browser actions skipped.")
82
+ return "\n".join(logs), generated_assets
83
+
84
+ with sync_playwright() as p:
85
+ log("🌐 Launching Headless Chromium...")
86
+ browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
87
+ page = browser.new_page()
88
+
89
+ try:
90
+ # Login Sequence
91
+ admin_url = f"{joomla_url.rstrip('/')}/administrator"
92
+ log(f"πŸ” Accessing {admin_url}...")
93
+ page.goto(admin_url)
94
+
95
+ # Intelligent Selector Handling
96
+ if page.is_visible('#mod-login-username'):
97
+ page.fill('#mod-login-username', username)
98
+ page.fill('#mod-login-password', password)
99
+ page.click('.login-button')
100
+ else:
101
+ # Fallback for standard Joomla
102
+ page.fill('input[name="username"]', username)
103
+ page.fill('input[name="passwd"]', password)
104
+ page.click('.btn-primary')
105
+
106
+ page.wait_for_load_state('networkidle')
107
+
108
+ if "dashboard" in page.url or "cpanel" in page.url:
109
+ log("βœ… Authentication Successful.")
110
+
111
+ # HERE is where we would parse the 'strategy' from the LLM
112
+ # to determine where to click next.
113
+ # For this demo, we log the success.
114
+ log("πŸ€– Ready to execute builder commands (Pending implementation of deep-link logic).")
115
+
116
+ else:
117
+ log("❌ Authentication Failed or Redirected.")
118
+
119
+ except Exception as e:
120
+ log(f"πŸ’₯ Runtime Error: {e}")
121
+ finally:
122
+ browser.close()
123
+ log("🏁 Mission Complete.")
124
+
125
+ return "\n".join(logs), generated_assets
126
+
127
+ # --- UI CONFIGURATION ---
128
+ with gr.Blocks(theme=gr.themes.Ocean(), title="UIKitV3 Automator") as demo:
129
+ gr.Markdown("""
130
+ # ⚑ UIKitV3-Automator (Agentic Mode)
131
+ **Powered by Qwen-2.5-Coder (Logic) & FLUX.1-dev (Vision)**
132
+ """)
133
+
134
+ with gr.Row():
135
+ with gr.Column():
136
+ url = gr.Textbox(label="Joomla URL", value="https://")
137
+ with gr.Row():
138
+ user = gr.Textbox(label="Username")
139
+ pwd = gr.Textbox(label="Password", type="password")
140
+
141
+ task = gr.Textbox(label="Command", lines=4, placeholder="Example: Go to the Article Manager, create a new article titled 'Summer Sale', and generate a hero image of a beach.")
142
+ dry = gr.Checkbox(label="Dry Run (Safe Mode)", value=True)
143
+ btn = gr.Button("Execute Agent", variant="primary")
144
+
145
+ with gr.Column():
146
+ console = gr.Code(label="Agent Logs", language="shell")
147
+ gallery = gr.Gallery(label="Generated Assets")
148
 
149
+ btn.click(execute_mission, inputs=[url, user, pwd, task, dry], outputs=[console, gallery])
 
 
 
 
 
 
 
 
150
 
151
  if __name__ == "__main__":
152
+ # Auto-install playwright browsers on first run
153
+ os.system("playwright install chromium")
154
+ demo.launch()