sasivedi/anycoder
0
1import os2import re3from http import HTTPStatus4from typing import Dict, List, Optional, Tuple5import base646import mimetypes7import PyPDF28import docx9import cv210import numpy as np11from PIL import Image12import pytesseract13import requests14from urllib.parse import urlparse, urljoin15from bs4 import BeautifulSoup16import html2text17import json18import time19import webbrowser20import urllib.parse21 22import gradio as gr23from huggingface_hub import InferenceClient24from tavily import TavilyClient25from huggingface_hub import HfApi26import tempfile27from openai import OpenAI28 29# Gradio supported languages for syntax highlighting30GRADIO_SUPPORTED_LANGUAGES = [31 "python", "c", "cpp", "markdown", "latex", "json", "html", "css", "javascript", "jinja2", "typescript", "yaml", "dockerfile", "shell", "r", "sql", "sql-msSQL", "sql-mySQL", "sql-mariaDB", "sql-sqlite", "sql-cassandra", "sql-plSQL", "sql-hive", "sql-pgSQL", "sql-gql", "sql-gpSQL", "sql-sparkSQL", "sql-esper", None32]33 34def get_gradio_language(language):35 return language if language in GRADIO_SUPPORTED_LANGUAGES else None36 37# Search/Replace Constants38SEARCH_START = "<<<<<<< SEARCH"39DIVIDER = "======="40REPLACE_END = ">>>>>>> REPLACE"41 42# Configuration43HTML_SYSTEM_PROMPT = """ONLY USE HTML, CSS AND JAVASCRIPT. If you want to use ICON make sure to import the library first. Try to create the best UI possible by using only HTML, CSS and JAVASCRIPT. MAKE IT RESPONSIVE USING MODERN CSS. Use as much as you can modern CSS for the styling, if you can't do something with modern CSS, then use custom CSS. Also, try to elaborate as much as you can, to create something unique. ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE44 45For website redesign tasks:46- Use the provided original HTML code as the starting point for redesign47- Preserve all original content, structure, and functionality48- Keep the same semantic HTML structure but enhance the styling49- Reuse all original images and their URLs from the HTML code50- Create a modern, responsive design with improved typography and spacing51- Use modern CSS frameworks and design patterns52- Ensure accessibility and mobile responsiveness53- Maintain the same navigation and user flow54- Enhance the visual design while keeping the original layout structure55 56If an image is provided, analyze it and use the visual information to better understand the user's requirements.57 58Always respond with code that can be executed or rendered directly.59 60Always output only the HTML code inside a ```html ... ``` code block, and do not include any explanations or extra text. Do NOT add the language name at the top of the code output."""61 62TRANSFORMERS_JS_SYSTEM_PROMPT = """You are an expert web developer creating a transformers.js application. You will generate THREE separate files: index.html, index.js, and style.css.63 64IMPORTANT: You MUST output ALL THREE files in the following format:65 66```html67<!-- index.html content here -->68```69 70```javascript71// index.js content here72```73 74```css75/* style.css content here */76```77 78Requirements:791. Create a modern, responsive web application using transformers.js802. Use the transformers.js library for AI/ML functionality813. Create a clean, professional UI with good user experience824. Make the application fully responsive for mobile devices835. Use modern CSS practices and JavaScript ES6+ features846. Include proper error handling and loading states857. Follow accessibility best practices86 87The index.html should contain the basic HTML structure and link to the CSS and JS files.88The index.js should contain all the JavaScript logic including transformers.js integration.89The style.css should contain all the styling for the application.90 91Always output only the three code blocks as shown above, and do not include any explanations or extra text."""92 93SVELTE_SYSTEM_PROMPT = """You are an expert Svelte developer creating a modern Svelte application. You will generate ONLY the custom files that need user-specific content.94 95IMPORTANT: You MUST output ONLY the custom files in the following format:96 97```svelte98<!-- src/App.svelte content here -->99```100 101```css102/* src/app.css content here */103```104 105```svelte106<!-- src/lib/Counter.svelte content here -->107```108 109Requirements:1101. Create a modern, responsive Svelte application1112. Use TypeScript for better type safety1123. Create a clean, professional UI with good user experience1134. Make the application fully responsive for mobile devices1145. Use modern CSS practices and Svelte best practices1156. Include proper error handling and loading states1167. Follow accessibility best practices1178. Use Svelte's reactive features effectively1189. Include proper component structure and organization119 120The files you generate are:121- src/App.svelte: Main application component (your custom app logic)122- src/app.css: Global styles (your custom styling)123- src/lib/Counter.svelte: Example component (your custom components)124 125The other files (index.html, package.json, vite.config.ts, tsconfig files, svelte.config.js, src/main.ts, src/vite-env.d.ts) are provided by the Svelte template and don't need to be generated.126 127Always output only the three code blocks as shown above, and do not include any explanations or extra text."""128 129SVELTE_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert Svelte developer creating a modern Svelte application. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific Svelte technologies.130 131You will generate ONLY the custom files that need user-specific content.132 133IMPORTANT: You MUST output ONLY the custom files in the following format:134 135```svelte136<!-- src/App.svelte content here -->137```138 139```css140/* src/app.css content here */141```142 143```svelte144<!-- src/lib/Counter.svelte content here -->145```146 147Requirements:1481. Create a modern, responsive Svelte application1492. Use TypeScript for better type safety1503. Create a clean, professional UI with good user experience1514. Make the application fully responsive for mobile devices1525. Use modern CSS practices and Svelte best practices1536. Include proper error handling and loading states1547. Follow accessibility best practices1558. Use Svelte's reactive features effectively1569. Include proper component structure and organization15710. Use web search to find the latest Svelte patterns, libraries, and best practices158 159The files you generate are:160- src/App.svelte: Main application component (your custom app logic)161- src/app.css: Global styles (your custom styling)162- src/lib/Counter.svelte: Example component (your custom components)163 164The other files (index.html, package.json, vite.config.ts, tsconfig files, svelte.config.js, src/main.ts, src/vite-env.d.ts) are provided by the Svelte template and don't need to be generated.165 166Always output only the three code blocks as shown above, and do not include any explanations or extra text."""167 168TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert web developer creating a transformers.js application. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for transformers.js.169 170You will generate THREE separate files: index.html, index.js, and style.css.171 172IMPORTANT: You MUST output ALL THREE files in the following format:173 174```html175<!-- index.html content here -->176```177 178```javascript179// index.js content here180```181 182```css183/* style.css content here */184```185 186Requirements:1871. Create a modern, responsive web application using transformers.js1882. Use the transformers.js library for AI/ML functionality1893. Use web search to find current best practices and latest transformers.js features1904. Create a clean, professional UI with good user experience1915. Make the application fully responsive for mobile devices1926. Use modern CSS practices and JavaScript ES6+ features1937. Include proper error handling and loading states1948. Follow accessibility best practices195 196The index.html should contain the basic HTML structure and link to the CSS and JS files.197The index.js should contain all the JavaScript logic including transformers.js integration.198The style.css should contain all the styling for the application.199 200Always output only the three code blocks as shown above, and do not include any explanations or extra text."""201 202GENERIC_SYSTEM_PROMPT = """You are an expert {language} developer. Write clean, idiomatic, and runnable {language} code for the user's request. If possible, include comments and best practices. Output ONLY the code inside a ``` code block, and do not include any explanations or extra text. If the user provides a file or other context, use it as a reference. If the code is for a script or app, make it as self-contained as possible. Do NOT add the language name at the top of the code output."""203 204# System prompt with search capability205HTML_SYSTEM_PROMPT_WITH_SEARCH = """ONLY USE HTML, CSS AND JAVASCRIPT. If you want to use ICON make sure to import the library first. Try to create the best UI possible by using only HTML, CSS and JAVASCRIPT. MAKE IT RESPONSIVE USING MODERN CSS. Use as much as you can modern CSS for the styling, if you can't do something with modern CSS, then use custom CSS. Also, try to elaborate as much as you can, to create something unique. ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE206 207You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies.208 209For website redesign tasks:210- Use the provided original HTML code as the starting point for redesign211- Preserve all original content, structure, and functionality212- Keep the same semantic HTML structure but enhance the styling213- Reuse all original images and their URLs from the HTML code214- Use web search to find current design trends and best practices for the specific type of website215- Create a modern, responsive design with improved typography and spacing216- Use modern CSS frameworks and design patterns217- Ensure accessibility and mobile responsiveness218- Maintain the same navigation and user flow219- Enhance the visual design while keeping the original layout structure220 221If an image is provided, analyze it and use the visual information to better understand the user's requirements.222 223Always respond with code that can be executed or rendered directly.224 225Always output only the HTML code inside a ```html ... ``` code block, and do not include any explanations or extra text. Do NOT add the language name at the top of the code output."""226 227GENERIC_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert {language} developer. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for {language}.228 229Write clean, idiomatic, and runnable {language} code for the user's request. If possible, include comments and best practices. Output ONLY the code inside a ``` code block, and do not include any explanations or extra text. If the user provides a file or other context, use it as a reference. If the code is for a script or app, make it as self-contained as possible. Do NOT add the language name at the top of the code output."""230 231# Follow-up system prompt for modifying existing HTML files232FollowUpSystemPrompt = f"""You are an expert web developer modifying an existing HTML file.233The user wants to apply changes based on their request.234You MUST output ONLY the changes required using the following SEARCH/REPLACE block format. Do NOT output the entire file.235Explain the changes briefly *before* the blocks if necessary, but the code changes THEMSELVES MUST be within the blocks.236Format Rules:2371. Start with {SEARCH_START}2382. Provide the exact lines from the current code that need to be replaced.2393. Use {DIVIDER} to separate the search block from the replacement.2404. Provide the new lines that should replace the original lines.2415. End with {REPLACE_END}2426. You can use multiple SEARCH/REPLACE blocks if changes are needed in different parts of the file.2437. To insert code, use an empty SEARCH block (only {SEARCH_START} and {DIVIDER} on their lines) if inserting at the very beginning, otherwise provide the line *before* the insertion point in the SEARCH block and include that line plus the new lines in the REPLACE block.2448. To delete code, provide the lines to delete in the SEARCH block and leave the REPLACE block empty (only {DIVIDER} and {REPLACE_END} on their lines).2459. IMPORTANT: The SEARCH block must *exactly* match the current code, including indentation and whitespace.246Example Modifying Code:247```248Some explanation...249{SEARCH_START}250 <h1>Old Title</h1>251{DIVIDER}252 <h1>New Title</h1>253{REPLACE_END}254{SEARCH_START}255 </body>256{DIVIDER}257 <script>console.log("Added script");</script>258 </body>259{REPLACE_END}260```261Example Deleting Code:262```263Removing the paragraph...264{SEARCH_START}265 <p>This paragraph will be deleted.</p>266{DIVIDER}267{REPLACE_END}268```"""269 270# Follow-up system prompt for modifying existing transformers.js applications271TransformersJSFollowUpSystemPrompt = f"""You are an expert web developer modifying an existing transformers.js application.272The user wants to apply changes based on their request.273You MUST output ONLY the changes required using the following SEARCH/REPLACE block format. Do NOT output the entire file.274Explain the changes briefly *before* the blocks if necessary, but the code changes THEMSELVES MUST be within the blocks.275 276The transformers.js application consists of three files: index.html, index.js, and style.css.277When making changes, specify which file you're modifying by starting your search/replace blocks with the file name.278 279Format Rules:2801. Start with {SEARCH_START}2812. Provide the exact lines from the current code that need to be replaced.2823. Use {DIVIDER} to separate the search block from the replacement.2834. Provide the new lines that should replace the original lines.2845. End with {REPLACE_END}2856. You can use multiple SEARCH/REPLACE blocks if changes are needed in different parts of the file.2867. To insert code, use an empty SEARCH block (only {SEARCH_START} and {DIVIDER} on their lines) if inserting at the very beginning, otherwise provide the line *before* the insertion point in the SEARCH block and include that line plus the new lines in the REPLACE block.2878. To delete code, provide the lines to delete in the SEARCH block and leave the REPLACE block empty (only {DIVIDER} and {REPLACE_END} on their lines).2889. IMPORTANT: The SEARCH block must *exactly* match the current code, including indentation and whitespace.289 290Example Modifying HTML:291```292Changing the title in index.html...293{SEARCH_START}294 <title>Old Title</title>295{DIVIDER}296 <title>New Title</title>297{REPLACE_END}298```299 300Example Modifying JavaScript:301```302Adding a new function to index.js...303{SEARCH_START}304// Existing code305{DIVIDER}306// Existing code307 308function newFunction() {{309 console.log("New function added");310}}311{REPLACE_END}312```313 314Example Modifying CSS:315```316Changing background color in style.css...317{SEARCH_START}318body {{319 background-color: white;320}}321{DIVIDER}322body {{323 background-color: #f0f0f0;324}}325{REPLACE_END}326```"""327 328# Available models329AVAILABLE_MODELS = [330 {331 "name": "Moonshot Kimi-K2",332 "id": "moonshotai/Kimi-K2-Instruct",333 "description": "Moonshot AI Kimi-K2-Instruct model for code generation and general tasks"334 },335 {336 "name": "DeepSeek V3",337 "id": "deepseek-ai/DeepSeek-V3-0324",338 "description": "DeepSeek V3 model for code generation"339 },340 {341 "name": "DeepSeek R1", 342 "id": "deepseek-ai/DeepSeek-R1-0528",343 "description": "DeepSeek R1 model for code generation"344 },345 {346 "name": "ERNIE-4.5-VL",347 "id": "baidu/ERNIE-4.5-VL-424B-A47B-Base-PT",348 "description": "ERNIE-4.5-VL model for multimodal code generation with image support"349 },350 {351 "name": "MiniMax M1",352 "id": "MiniMaxAI/MiniMax-M1-80k",353 "description": "MiniMax M1 model for code generation and general tasks"354 },355 {356 "name": "Qwen3-235B-A22B",357 "id": "Qwen/Qwen3-235B-A22B",358 "description": "Qwen3-235B-A22B model for code generation and general tasks"359 },360 {361 "name": "SmolLM3-3B",362 "id": "HuggingFaceTB/SmolLM3-3B",363 "description": "SmolLM3-3B model for code generation and general tasks"364 },365 {366 "name": "GLM-4.1V-9B-Thinking",367 "id": "THUDM/GLM-4.1V-9B-Thinking",368 "description": "GLM-4.1V-9B-Thinking model for multimodal code generation with image support"369 },370 {371 "name": "Qwen3-235B-A22B-Instruct-2507",372 "id": "Qwen/Qwen3-235B-A22B-Instruct-2507",373 "description": "Qwen3-235B-A22B-Instruct-2507 model for code generation and general tasks"374 },375 {376 "name": "Qwen3-Coder-480B-A35B",377 "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct",378 "description": "Qwen3-Coder-480B-A35B-Instruct model for advanced code generation and programming tasks"379 }380]381 382DEMO_LIST = [383 {384 "title": "Todo App",385 "description": "Create a simple todo application with add, delete, and mark as complete functionality"386 },387 {388 "title": "Calculator",389 "description": "Build a basic calculator with addition, subtraction, multiplication, and division"390 },391 {392 "title": "Chat Interface",393 "description": "Build a chat interface with message history and user input"394 },395 {396 "title": "E-commerce Product Card",397 "description": "Create a product card component for an e-commerce website"398 },399 {400 "title": "Login Form",401 "description": "Build a responsive login form with validation"402 },403 {404 "title": "Dashboard Layout",405 "description": "Create a dashboard layout with sidebar navigation and main content area"406 },407 {408 "title": "Data Table",409 "description": "Build a data table with sorting and filtering capabilities"410 },411 {412 "title": "Image Gallery",413 "description": "Create an image gallery with lightbox functionality and responsive grid layout"414 },415 {416 "title": "UI from Image",417 "description": "Upload an image of a UI design and I'll generate the HTML/CSS code for it"418 },419 {420 "title": "Extract Text from Image",421 "description": "Upload an image containing text and I'll extract and process the text content"422 },423 {424 "title": "Website Redesign",425 "description": "Enter a website URL to extract its content and redesign it with a modern, responsive layout"426 },427 {428 "title": "Modify HTML",429 "description": "After generating HTML, ask me to modify it with specific changes using search/replace format"430 },431 {432 "title": "Search/Replace Example",433 "description": "Generate HTML first, then ask: 'Change the title to My New Title' or 'Add a blue background to the body'"434 },435 {436 "title": "Transformers.js App",437 "description": "Create a transformers.js application with AI/ML functionality using the transformers.js library"438 },439 {440 "title": "Svelte App",441 "description": "Create a modern Svelte application with TypeScript, Vite, and responsive design"442 }443]444 445# HF Inference Client446HF_TOKEN = os.getenv('HF_TOKEN')447if not HF_TOKEN:448 raise RuntimeError("HF_TOKEN environment variable is not set. Please set it to your Hugging Face API token.")449 450def get_inference_client(model_id, provider="auto"):451 """Return an InferenceClient with provider based on model_id and user selection."""452 if model_id == "moonshotai/Kimi-K2-Instruct":453 provider = "groq"454 return InferenceClient(455 provider=provider,456 api_key=HF_TOKEN,457 bill_to="huggingface"458 )459 460# Type definitions461History = List[Tuple[str, str]]462Messages = List[Dict[str, str]]463 464# Tavily Search Client465TAVILY_API_KEY = os.getenv('TAVILY_API_KEY')466tavily_client = None467if TAVILY_API_KEY:468 try:469 tavily_client = TavilyClient(api_key=TAVILY_API_KEY)470 except Exception as e:471 print(f"Failed to initialize Tavily client: {e}")472 tavily_client = None473 474def history_to_messages(history: History, system: str) -> Messages:475 messages = [{'role': 'system', 'content': system}]476 for h in history:477 # Handle multimodal content in history478 user_content = h[0]479 if isinstance(user_content, list):480 # Extract text from multimodal content481 text_content = ""482 for item in user_content:483 if isinstance(item, dict) and item.get("type") == "text":484 text_content += item.get("text", "")485 user_content = text_content if text_content else str(user_content)486 487 messages.append({'role': 'user', 'content': user_content})488 messages.append({'role': 'assistant', 'content': h[1]})489 return messages490 491def messages_to_history(messages: Messages) -> Tuple[str, History]:492 assert messages[0]['role'] == 'system'493 history = []494 for q, r in zip(messages[1::2], messages[2::2]):495 # Extract text content from multimodal messages for history496 user_content = q['content']497 if isinstance(user_content, list):498 text_content = ""499 for item in user_content:500 if isinstance(item, dict) and item.get("type") == "text":501 text_content += item.get("text", "")502 user_content = text_content if text_content else str(user_content)503 504 history.append([user_content, r['content']])505 return history506 507def history_to_chatbot_messages(history: History) -> List[Dict[str, str]]:508 """Convert history tuples to chatbot message format"""509 messages = []510 for user_msg, assistant_msg in history:511 # Handle multimodal content512 if isinstance(user_msg, list):513 text_content = ""514 for item in user_msg:515 if isinstance(item, dict) and item.get("type") == "text":516 text_content += item.get("text", "")517 user_msg = text_content if text_content else str(user_msg)518 519 messages.append({"role": "user", "content": user_msg})520 messages.append({"role": "assistant", "content": assistant_msg})521 return messages522 523def remove_code_block(text):524 # Try to match code blocks with language markers525 patterns = [526 r'```(?:html|HTML)\n([\s\S]+?)\n```', # Match ```html or ```HTML527 r'```\n([\s\S]+?)\n```', # Match code blocks without language markers528 r'```([\s\S]+?)```' # Match code blocks without line breaks529 ]530 for pattern in patterns:531 match = re.search(pattern, text, re.DOTALL)532 if match:533 extracted = match.group(1).strip()534 # Remove a leading language marker line (e.g., 'python') if present535 if extracted.split('\n', 1)[0].strip().lower() in ['python', 'html', 'css', 'javascript', 'json', 'c', 'cpp', 'markdown', 'latex', 'jinja2', 'typescript', 'yaml', 'dockerfile', 'shell', 'r', 'sql', 'sql-mssql', 'sql-mysql', 'sql-mariadb', 'sql-sqlite', 'sql-cassandra', 'sql-plSQL', 'sql-hive', 'sql-pgsql', 'sql-gql', 'sql-gpsql', 'sql-sparksql', 'sql-esper']:536 return extracted.split('\n', 1)[1] if '\n' in extracted else ''537 return extracted538 # If no code block is found, check if the entire text is HTML539 if text.strip().startswith('<!DOCTYPE html>') or text.strip().startswith('<html') or text.strip().startswith('<'):540 return text.strip()541 # Special handling for python: remove python marker542 if text.strip().startswith('```python'):543 return text.strip()[9:-3].strip()544 # Remove a leading language marker line if present (fallback)545 lines = text.strip().split('\n', 1)546 if lines[0].strip().lower() in ['python', 'html', 'css', 'javascript', 'json', 'c', 'cpp', 'markdown', 'latex', 'jinja2', 'typescript', 'yaml', 'dockerfile', 'shell', 'r', 'sql', 'sql-mssql', 'sql-mysql', 'sql-mariadb', 'sql-sqlite', 'sql-cassandra', 'sql-plSQL', 'sql-hive', 'sql-pgsql', 'sql-gql', 'sql-gpsql', 'sql-sparksql', 'sql-esper']:547 return lines[1] if len(lines) > 1 else ''548 return text.strip()549 550def parse_transformers_js_output(text):551 """Parse transformers.js output and extract the three files (index.html, index.js, style.css)"""552 files = {553 'index.html': '',554 'index.js': '',555 'style.css': ''556 }557 558 # Patterns to match the three code blocks559 html_pattern = r'```html\s*\n([\s\S]+?)\n```'560 js_pattern = r'```javascript\s*\n([\s\S]+?)\n```'561 css_pattern = r'```css\s*\n([\s\S]+?)\n```'562 563 # Extract HTML content564 html_match = re.search(html_pattern, text, re.IGNORECASE)565 if html_match:566 files['index.html'] = html_match.group(1).strip()567 568 # Extract JavaScript content569 js_match = re.search(js_pattern, text, re.IGNORECASE)570 if js_match:571 files['index.js'] = js_match.group(1).strip()572 573 # Extract CSS content574 css_match = re.search(css_pattern, text, re.IGNORECASE)575 if css_match:576 files['style.css'] = css_match.group(1).strip()577 578 # Fallback: support === index.html === format if any file is missing579 if not (files['index.html'] and files['index.js'] and files['style.css']):580 # Use regex to extract sections581 html_fallback = re.search(r'===\s*index\.html\s*===\n([\s\S]+?)(?=\n===|$)', text, re.IGNORECASE)582 js_fallback = re.search(r'===\s*index\.js\s*===\n([\s\S]+?)(?=\n===|$)', text, re.IGNORECASE)583 css_fallback = re.search(r'===\s*style\.css\s*===\n([\s\S]+?)(?=\n===|$)', text, re.IGNORECASE)584 if html_fallback:585 files['index.html'] = html_fallback.group(1).strip()586 if js_fallback:587 files['index.js'] = js_fallback.group(1).strip()588 if css_fallback:589 files['style.css'] = css_fallback.group(1).strip()590 591 return files592 593def format_transformers_js_output(files):594 """Format the three files into a single display string"""595 output = []596 output.append("=== index.html ===")597 output.append(files['index.html'])598 output.append("\n=== index.js ===")599 output.append(files['index.js'])600 output.append("\n=== style.css ===")601 output.append(files['style.css'])602 return '\n'.join(output)603 604def parse_svelte_output(text):605 """Parse Svelte output to extract individual files"""606 files = {607 'src/App.svelte': '',608 'src/app.css': '',609 'src/lib/Counter.svelte': ''610 }611 612 # Split by code blocks613 import re614 code_blocks = re.findall(r'```(?:svelte|css)\n(.*?)```', text, re.DOTALL)615 616 # Handle partial generation - assign what we have617 if len(code_blocks) >= 1:618 files['src/App.svelte'] = code_blocks[0].strip()619 if len(code_blocks) >= 2:620 files['src/app.css'] = code_blocks[1].strip()621 if len(code_blocks) >= 3:622 files['src/lib/Counter.svelte'] = code_blocks[2].strip()623 624 return files625 626def format_svelte_output(files):627 """Format Svelte files into a single display string"""628 output = []629 output.append("=== src/App.svelte ===")630 output.append(files['src/App.svelte'])631 output.append("\n=== src/app.css ===")632 output.append(files['src/app.css'])633 output.append("\n=== src/lib/Counter.svelte ===")634 output.append(files['src/lib/Counter.svelte'])635 return '\n'.join(output)636 637def history_render(history: History):638 return gr.update(visible=True), history639 640def clear_history():641 return [], [], None, "" # Empty lists for both tuple format and chatbot messages, None for file, empty string for website URL642 643def update_image_input_visibility(model):644 """Update image input visibility based on selected model"""645 is_ernie_vl = model.get("id") == "baidu/ERNIE-4.5-VL-424B-A47B-Base-PT"646 is_glm_vl = model.get("id") == "THUDM/GLM-4.1V-9B-Thinking"647 return gr.update(visible=is_ernie_vl or is_glm_vl)648 649def process_image_for_model(image):650 """Convert image to base64 for model input"""651 if image is None:652 return None653 654 # Convert numpy array to PIL Image if needed655 import io656 import base64657 import numpy as np658 from PIL import Image659 660 # Handle numpy array from Gradio661 if isinstance(image, np.ndarray):662 image = Image.fromarray(image)663 664 buffer = io.BytesIO()665 image.save(buffer, format='PNG')666 img_str = base64.b64encode(buffer.getvalue()).decode()667 return f"data:image/png;base64,{img_str}"668 669def create_multimodal_message(text, image=None):670 """Create a multimodal message with text and optional image"""671 if image is None:672 return {"role": "user", "content": text}673 674 content = [675 {676 "type": "text",677 "text": text678 },679 {680 "type": "image_url",681 "image_url": {682 "url": process_image_for_model(image)683 }684 }685 ]686 687 return {"role": "user", "content": content}688 689def apply_search_replace_changes(original_content: str, changes_text: str) -> str:690 """Apply search/replace changes to content (HTML, Python, etc.)"""691 if not changes_text.strip():692 return original_content693 694 # Split the changes text into individual search/replace blocks695 blocks = []696 current_block = ""697 lines = changes_text.split('\n')698 699 for line in lines:700 if line.strip() == SEARCH_START:701 if current_block.strip():702 blocks.append(current_block.strip())703 current_block = line + '\n'704 elif line.strip() == REPLACE_END:705 current_block += line + '\n'706 blocks.append(current_block.strip())707 current_block = ""708 else:709 current_block += line + '\n'710 711 if current_block.strip():712 blocks.append(current_block.strip())713 714 modified_content = original_content715 716 for block in blocks:717 if not block.strip():718 continue719 720 # Parse the search/replace block721 lines = block.split('\n')722 search_lines = []723 replace_lines = []724 in_search = False725 in_replace = False726 727 for line in lines:728 if line.strip() == SEARCH_START:729 in_search = True730 in_replace = False731 elif line.strip() == DIVIDER:732 in_search = False733 in_replace = True734 elif line.strip() == REPLACE_END:735 in_replace = False736 elif in_search:737 search_lines.append(line)738 elif in_replace:739 replace_lines.append(line)740 741 # Apply the search/replace742 if search_lines:743 search_text = '\n'.join(search_lines).strip()744 replace_text = '\n'.join(replace_lines).strip()745 746 if search_text in modified_content:747 modified_content = modified_content.replace(search_text, replace_text)748 else:749 print(f"Warning: Search text not found in content: {search_text[:100]}...")750 751 return modified_content752 753def apply_transformers_js_search_replace_changes(original_formatted_content: str, changes_text: str) -> str:754 """Apply search/replace changes to transformers.js formatted content (three files)"""755 if not changes_text.strip():756 return original_formatted_content757 758 # Parse the original formatted content to get the three files759 files = parse_transformers_js_output(original_formatted_content)760 761 # Split the changes text into individual search/replace blocks762 blocks = []763 current_block = ""764 lines = changes_text.split('\n')765 766 for line in lines:767 if line.strip() == SEARCH_START:768 if current_block.strip():769 blocks.append(current_block.strip())770 current_block = line + '\n'771 elif line.strip() == REPLACE_END:772 current_block += line + '\n'773 blocks.append(current_block.strip())774 current_block = ""775 else:776 current_block += line + '\n'777 778 if current_block.strip():779 blocks.append(current_block.strip())780 781 # Process each block and apply changes to the appropriate file782 for block in blocks:783 if not block.strip():784 continue785 786 # Parse the search/replace block787 lines = block.split('\n')788 search_lines = []789 replace_lines = []790 in_search = False791 in_replace = False792 target_file = None793 794 for line in lines:795 if line.strip() == SEARCH_START:796 in_search = True797 in_replace = False798 elif line.strip() == DIVIDER:799 in_search = False800 in_replace = True801 elif line.strip() == REPLACE_END:802 in_replace = False803 elif in_search:804 search_lines.append(line)805 elif in_replace:806 replace_lines.append(line)807 808 # Determine which file this change targets based on the search content809 if search_lines:810 search_text = '\n'.join(search_lines).strip()811 replace_text = '\n'.join(replace_lines).strip()812 813 # Check which file contains the search text814 if search_text in files['index.html']:815 target_file = 'index.html'816 elif search_text in files['index.js']:817 target_file = 'index.js'818 elif search_text in files['style.css']:819 target_file = 'style.css'820 821 # Apply the change to the target file822 if target_file and search_text in files[target_file]:823 files[target_file] = files[target_file].replace(search_text, replace_text)824 else:825 print(f"Warning: Search text not found in any transformers.js file: {search_text[:100]}...")826 827 # Reformat the modified files828 return format_transformers_js_output(files)829 830# Updated for faster Tavily search and closer prompt usage831# Uses 'advanced' search_depth and auto_parameters=True for speed and relevance832 833def perform_web_search(query: str, max_results: int = 5, include_domains=None, exclude_domains=None) -> str:834 """Perform web search using Tavily with default parameters"""835 if not tavily_client:836 return "Web search is not available. Please set the TAVILY_API_KEY environment variable."837 838 try:839 # Use Tavily defaults with advanced search depth for better results840 search_params = {841 "search_depth": "advanced",842 "max_results": min(max(1, max_results), 20)843 }844 if include_domains is not None:845 search_params["include_domains"] = include_domains846 if exclude_domains is not None:847 search_params["exclude_domains"] = exclude_domains848 849 response = tavily_client.search(query, **search_params)850 851 search_results = []852 for result in response.get('results', []):853 title = result.get('title', 'No title')854 url = result.get('url', 'No URL')855 content = result.get('content', 'No content')856 search_results.append(f"Title: {title}\nURL: {url}\nContent: {content}\n")857 858 if search_results:859 return "Web Search Results:\n\n" + "\n---\n".join(search_results)860 else:861 return "No search results found."862 863 except Exception as e:864 return f"Search error: {str(e)}"865 866def enhance_query_with_search(query: str, enable_search: bool) -> str:867 """Enhance the query with web search results if search is enabled"""868 if not enable_search or not tavily_client:869 return query870 871 # Perform search to get relevant information872 search_results = perform_web_search(query)873 874 # Combine original query with search results875 enhanced_query = f"""Original Query: {query}876 877{search_results}878 879Please use the search results above to help create the requested application with the most up-to-date information and best practices."""880 881 return enhanced_query882 883def send_to_sandbox(code):884 # Add a wrapper to inject necessary permissions and ensure full HTML885 wrapped_code = f"""886 <!DOCTYPE html>887 <html>888 <head>889 <meta charset=\"UTF-8\">890 <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">891 <script>892 // Safe localStorage polyfill893 const safeStorage = {{894 _data: {{}},895 getItem: function(key) {{ return this._data[key] || null; }},896 setItem: function(key, value) {{ this._data[key] = value; }},897 removeItem: function(key) {{ delete this._data[key]; }},898 clear: function() {{ this._data = {{}}; }}899 }};900 Object.defineProperty(window, 'localStorage', {{901 value: safeStorage,902 writable: false903 }});904 window.onerror = function(message, source, lineno, colno, error) {{905 console.error('Error:', message);906 }};907 </script>908 </head>909 <body>910 {code}911 </body>912 </html>913 """914 encoded_html = base64.b64encode(wrapped_code.encode('utf-8')).decode('utf-8')915 data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"916 iframe = f'<iframe src="{data_uri}" width="100%" height="920px" sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-presentation" allow="display-capture"></iframe>'917 return iframe918 919def demo_card_click(e: gr.EventData):920 try:921 # Get the index from the event data922 if hasattr(e, '_data') and e._data:923 # Try different ways to get the index924 if 'index' in e._data:925 index = e._data['index']926 elif 'component' in e._data and 'index' in e._data['component']:927 index = e._data['component']['index']928 elif 'target' in e._data and 'index' in e._data['target']:929 index = e._data['target']['index']930 else:931 # If we can't get the index, try to extract it from the card data932 index = 0933 else:934 index = 0935 936 # Ensure index is within bounds937 if index >= len(DEMO_LIST):938 index = 0939 940 return DEMO_LIST[index]['description']941 except (KeyError, IndexError, AttributeError) as e:942 # Return the first demo description as fallback943 return DEMO_LIST[0]['description']944 945def extract_text_from_image(image_path):946 """Extract text from image using OCR"""947 try:948 # Check if tesseract is available949 try:950 pytesseract.get_tesseract_version()951 except Exception:952 return "Error: Tesseract OCR is not installed. Please install Tesseract to extract text from images. See install_tesseract.md for instructions."953 954 # Read image using OpenCV955 image = cv2.imread(image_path)956 if image is None:957 return "Error: Could not read image file"958 959 # Convert to RGB (OpenCV uses BGR)960 image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)961 962 # Preprocess image for better OCR results963 # Convert to grayscale964 gray = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2GRAY)965 966 # Apply thresholding to get binary image967 _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)968 969 # Extract text using pytesseract970 text = pytesseract.image_to_string(binary, config='--psm 6')971 972 return text.strip() if text.strip() else "No text found in image"973 974 except Exception as e:975 return f"Error extracting text from image: {e}"976 977def extract_text_from_file(file_path):978 if not file_path:979 return ""980 mime, _ = mimetypes.guess_type(file_path)981 ext = os.path.splitext(file_path)[1].lower()982 try:983 if ext == ".pdf":984 with open(file_path, "rb") as f:985 reader = PyPDF2.PdfReader(f)986 return "\n".join(page.extract_text() or "" for page in reader.pages)987 elif ext in [".txt", ".md"]:988 with open(file_path, "r", encoding="utf-8") as f:989 return f.read()990 elif ext == ".csv":991 with open(file_path, "r", encoding="utf-8") as f:992 return f.read()993 elif ext == ".docx":994 doc = docx.Document(file_path)995 return "\n".join([para.text for para in doc.paragraphs])996 elif ext.lower() in [".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif", ".gif", ".webp"]:997 return extract_text_from_image(file_path)998 else:999 return ""1000 except Exception as e:1001 return f"Error extracting text: {e}"1002 1003def extract_website_content(url: str) -> str:1004 """Extract HTML code and content from a website URL"""1005 try:1006 # Validate URL1007 parsed_url = urlparse(url)1008 if not parsed_url.scheme:1009 url = "https://" + url1010 parsed_url = urlparse(url)1011 1012 if not parsed_url.netloc:1013 return "Error: Invalid URL provided"1014 1015 # Set comprehensive headers to mimic a real browser request1016 headers = {1017 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',1018 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',1019 'Accept-Language': 'en-US,en;q=0.9',1020 'Accept-Encoding': 'gzip, deflate, br',1021 'DNT': '1',1022 'Connection': 'keep-alive',1023 'Upgrade-Insecure-Requests': '1',1024 'Sec-Fetch-Dest': 'document',1025 'Sec-Fetch-Mode': 'navigate',1026 'Sec-Fetch-Site': 'none',1027 'Sec-Fetch-User': '?1',1028 'Cache-Control': 'max-age=0'1029 }1030 1031 # Create a session to maintain cookies and handle redirects1032 session = requests.Session()1033 session.headers.update(headers)1034 1035 # Make the request with retry logic1036 max_retries = 31037 for attempt in range(max_retries):1038 try:1039 response = session.get(url, timeout=15, allow_redirects=True)1040 response.raise_for_status()1041 break1042 except requests.exceptions.HTTPError as e:1043 if e.response.status_code == 403 and attempt < max_retries - 1:1044 # Try with different User-Agent on 4031045 session.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'1046 continue1047 else:1048 raise1049 1050 # Get the raw HTML content with proper encoding1051 try:1052 # Try to get the content with automatic encoding detection1053 response.encoding = response.apparent_encoding1054 raw_html = response.text1055 except:1056 # Fallback to UTF-8 if encoding detection fails1057 raw_html = response.content.decode('utf-8', errors='ignore')1058 1059 # Debug: Check if we got valid HTML1060 if not raw_html.strip().startswith('<!DOCTYPE') and not raw_html.strip().startswith('<html'):1061 print(f"Warning: Response doesn't look like HTML. First 200 chars: {raw_html[:200]}")1062 print(f"Response headers: {dict(response.headers)}")1063 print(f"Response encoding: {response.encoding}")1064 print(f"Apparent encoding: {response.apparent_encoding}")1065 1066 # Try alternative approaches1067 try:1068 raw_html = response.content.decode('latin-1', errors='ignore')1069 print("Tried latin-1 decoding")1070 except:1071 try:1072 raw_html = response.content.decode('utf-8', errors='ignore')1073 print("Tried UTF-8 decoding")1074 except:1075 raw_html = response.content.decode('cp1252', errors='ignore')1076 print("Tried cp1252 decoding")1077 1078 # Parse HTML content for analysis1079 soup = BeautifulSoup(raw_html, 'html.parser')1080 1081 # Check if this is a JavaScript-heavy site1082 script_tags = soup.find_all('script')1083 if len(script_tags) > 10:1084 print(f"Warning: This site has {len(script_tags)} script tags - it may be a JavaScript-heavy site")1085 print("The content might be loaded dynamically and not available in the initial HTML")1086 1087 # Extract title1088 title = soup.find('title')1089 title_text = title.get_text().strip() if title else "No title found"1090 1091 # Extract meta description1092 meta_desc = soup.find('meta', attrs={'name': 'description'})1093 description = meta_desc.get('content', '') if meta_desc else ""1094 1095 # Extract main content areas for analysis1096 content_sections = []1097 main_selectors = [1098 'main', 'article', '.content', '.main-content', '.post-content',1099 '#content', '#main', '.entry-content', '.post-body'1100 ]1101 1102 for selector in main_selectors:1103 elements = soup.select(selector)1104 for element in elements:1105 text = element.get_text().strip()1106 if len(text) > 100: # Only include substantial content1107 content_sections.append(text)1108 1109 # Extract navigation links for analysis1110 nav_links = []1111 nav_elements = soup.find_all(['nav', 'header'])1112 for nav in nav_elements:1113 links = nav.find_all('a')1114 for link in links:1115 link_text = link.get_text().strip()1116 link_href = link.get('href', '')1117 if link_text and link_href:1118 nav_links.append(f"{link_text}: {link_href}")1119 1120 # Extract and fix image URLs in the HTML1121 img_elements = soup.find_all('img')1122 for img in img_elements:1123 src = img.get('src', '')1124 if src:1125 # Handle different URL formats1126 if src.startswith('//'):1127 # Protocol-relative URL1128 absolute_src = 'https:' + src1129 img['src'] = absolute_src1130 elif src.startswith('/'):1131 # Root-relative URL1132 absolute_src = urljoin(url, src)1133 img['src'] = absolute_src1134 elif not src.startswith(('http://', 'https://')):1135 # Relative URL1136 absolute_src = urljoin(url, src)1137 img['src'] = absolute_src1138 # If it's already absolute, keep it as is1139 1140 # Also check for data-src (lazy loading) and other common attributes1141 data_src = img.get('data-src', '')1142 if data_src and not src:1143 # Use data-src if src is empty1144 if data_src.startswith('//'):1145 absolute_data_src = 'https:' + data_src1146 img['src'] = absolute_data_src1147 elif data_src.startswith('/'):1148 absolute_data_src = urljoin(url, data_src)1149 img['src'] = absolute_data_src1150 elif not data_src.startswith(('http://', 'https://')):1151 absolute_data_src = urljoin(url, data_src)1152 img['src'] = absolute_data_src1153 else:1154 img['src'] = data_src1155 1156 # Also fix background image URLs in style attributes1157 elements_with_style = soup.find_all(attrs={'style': True})1158 for element in elements_with_style:1159 style_attr = element.get('style', '')1160 # Find and replace relative URLs in background-image1161 import re1162 bg_pattern = r'background-image:\s*url\(["\']?([^"\']+)["\']?\)'1163 matches = re.findall(bg_pattern, style_attr, re.IGNORECASE)1164 for match in matches:1165 if match:1166 if match.startswith('//'):1167 absolute_bg = 'https:' + match1168 style_attr = style_attr.replace(match, absolute_bg)1169 elif match.startswith('/'):1170 absolute_bg = urljoin(url, match)1171 style_attr = style_attr.replace(match, absolute_bg)1172 elif not match.startswith(('http://', 'https://')):1173 absolute_bg = urljoin(url, match)1174 style_attr = style_attr.replace(match, absolute_bg)1175 element['style'] = style_attr1176 1177 # Fix background images in <style> tags1178 style_elements = soup.find_all('style')1179 for style in style_elements:1180 if style.string:1181 style_content = style.string1182 # Find and replace relative URLs in background-image1183 bg_pattern = r'background-image:\s*url\(["\']?([^"\']+)["\']?\)'1184 matches = re.findall(bg_pattern, style_content, re.IGNORECASE)1185 for match in matches:1186 if match:1187 if match.startswith('//'):1188 absolute_bg = 'https:' + match1189 style_content = style_content.replace(match, absolute_bg)1190 elif match.startswith('/'):1191 absolute_bg = urljoin(url, match)1192 style_content = style_content.replace(match, absolute_bg)1193 elif not match.startswith(('http://', 'https://')):1194 absolute_bg = urljoin(url, match)1195 style_content = style_content.replace(match, absolute_bg)1196 style.string = style_content1197 1198 # Extract images for analysis (after fixing URLs)1199 images = []1200 img_elements = soup.find_all('img')