Spaces:
Running
Running
website design feature
Browse files- README.md +56 -0
- app.py +238 -62
- requirements.txt +4 -1
README.md
CHANGED
@@ -22,6 +22,7 @@ AnyCoder is an AI-powered code generator that helps you create applications by d
|
|
22 |
- **Multi-Model Support**: Choose from various AI models including DeepSeek, ERNIE-4.5-VL, MiniMax, and Qwen
|
23 |
- **Image-to-Code**: Upload UI design images and get corresponding HTML/CSS code (ERNIE-4.5-VL model)
|
24 |
- **Image Text Extraction**: Upload images and extract text using OCR for processing
|
|
|
25 |
- **Live Preview**: See your generated code in action with the built-in sandbox
|
26 |
- **Web Search Integration**: Enable real-time web search to get the latest information and best practices
|
27 |
- **Chat History**: Keep track of your conversations and generated code
|
@@ -93,6 +94,61 @@ To use the image text extraction feature, you need to install Tesseract OCR on y
|
|
93 |
- The application will extract the text and include it in your prompt
|
94 |
- You can then ask the AI to process, summarize, or work with the extracted text
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
## Available Models
|
97 |
|
98 |
- **DeepSeek V3**: Advanced code generation model
|
|
|
22 |
- **Multi-Model Support**: Choose from various AI models including DeepSeek, ERNIE-4.5-VL, MiniMax, and Qwen
|
23 |
- **Image-to-Code**: Upload UI design images and get corresponding HTML/CSS code (ERNIE-4.5-VL model)
|
24 |
- **Image Text Extraction**: Upload images and extract text using OCR for processing
|
25 |
+
- **Website Redesign**: Enter a website URL to extract content and redesign it with modern, responsive layouts
|
26 |
- **Live Preview**: See your generated code in action with the built-in sandbox
|
27 |
- **Web Search Integration**: Enable real-time web search to get the latest information and best practices
|
28 |
- **Chat History**: Keep track of your conversations and generated code
|
|
|
94 |
- The application will extract the text and include it in your prompt
|
95 |
- You can then ask the AI to process, summarize, or work with the extracted text
|
96 |
|
97 |
+
## Website Redesign Feature
|
98 |
+
|
99 |
+
The website redesign feature allows you to extract content from existing websites and generate modern, responsive redesigns. This feature:
|
100 |
+
|
101 |
+
1. **Extracts Website Content**: Automatically scrapes the target website to extract:
|
102 |
+
- Page title and meta description
|
103 |
+
- Navigation menu structure
|
104 |
+
- Main content sections
|
105 |
+
- Images and their descriptions
|
106 |
+
- Overall page structure and purpose
|
107 |
+
|
108 |
+
2. **Generates Modern Redesigns**: Creates improved versions with:
|
109 |
+
- Modern, responsive layouts
|
110 |
+
- Enhanced user experience
|
111 |
+
- Better accessibility
|
112 |
+
- Mobile-first design principles
|
113 |
+
- Current design trends and best practices
|
114 |
+
|
115 |
+
### How to Use Website Redesign
|
116 |
+
|
117 |
+
1. **Enter a Website URL**: In the "🌐 Website URL (for redesign)" field, enter the URL of the website you want to redesign
|
118 |
+
- Example: `https://example.com`
|
119 |
+
- The URL can be with or without `https://`
|
120 |
+
|
121 |
+
2. **Add Custom Requirements**: Optionally describe specific improvements you want:
|
122 |
+
- "Make it more modern and minimalist"
|
123 |
+
- "Add a dark mode toggle"
|
124 |
+
- "Improve the mobile layout"
|
125 |
+
- "Use a different color scheme"
|
126 |
+
|
127 |
+
3. **Enable Web Search**: Toggle the web search feature to get the latest design trends and best practices
|
128 |
+
|
129 |
+
4. **Generate**: Click "Generate" to create your redesigned website
|
130 |
+
|
131 |
+
### Example Usage
|
132 |
+
|
133 |
+
```
|
134 |
+
URL: https://example.com
|
135 |
+
Description: Redesign this website with a modern, minimalist approach. Use a clean typography and improve the mobile experience.
|
136 |
+
```
|
137 |
+
|
138 |
+
The AI will analyze the original website content and create a completely redesigned version that maintains the core functionality while providing a better user experience.
|
139 |
+
|
140 |
+
### Supported Websites
|
141 |
+
|
142 |
+
The feature works with most public websites, including:
|
143 |
+
- Business websites
|
144 |
+
- Portfolio sites
|
145 |
+
- Blog platforms
|
146 |
+
- E-commerce sites
|
147 |
+
- Landing pages
|
148 |
+
- Documentation sites
|
149 |
+
|
150 |
+
**Note**: Some websites may block automated access or require JavaScript to load content. In such cases, the extraction may be limited.
|
151 |
+
|
152 |
## Available Models
|
153 |
|
154 |
- **DeepSeek V3**: Advanced code generation model
|
app.py
CHANGED
@@ -10,6 +10,10 @@ import cv2
|
|
10 |
import numpy as np
|
11 |
from PIL import Image
|
12 |
import pytesseract
|
|
|
|
|
|
|
|
|
13 |
|
14 |
import gradio as gr
|
15 |
from huggingface_hub import InferenceClient
|
@@ -24,6 +28,13 @@ When asked to create an application, you should:
|
|
24 |
4. Include necessary comments and documentation
|
25 |
5. Ensure the code is functional and follows best practices
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
If an image is provided, analyze it and use the visual information to better understand the user's requirements.
|
28 |
|
29 |
Always respond with code that can be executed or rendered directly.
|
@@ -40,6 +51,14 @@ When asked to create an application, you should:
|
|
40 |
5. Include necessary comments and documentation
|
41 |
6. Ensure the code is functional and follows best practices
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
If an image is provided, analyze it and use the visual information to better understand the user's requirements.
|
44 |
|
45 |
Always respond with code that can be executed or rendered directly.
|
@@ -124,6 +143,10 @@ DEMO_LIST = [
|
|
124 |
{
|
125 |
"title": "Extract Text from Image",
|
126 |
"description": "Upload an image containing text and I'll extract and process the text content"
|
|
|
|
|
|
|
|
|
127 |
}
|
128 |
]
|
129 |
|
@@ -218,7 +241,7 @@ def history_render(history: History):
|
|
218 |
return gr.update(visible=True), history
|
219 |
|
220 |
def clear_history():
|
221 |
-
return [], [] # Empty lists for both tuple format and chatbot messages
|
222 |
|
223 |
def update_image_input_visibility(model):
|
224 |
"""Update image input visibility based on selected model"""
|
@@ -438,7 +461,123 @@ def extract_text_from_file(file_path):
|
|
438 |
except Exception as e:
|
439 |
return f"Error extracting text: {e}"
|
440 |
|
441 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
442 |
if query is None:
|
443 |
query = ''
|
444 |
if _history is None:
|
@@ -456,6 +595,16 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
|
|
456 |
file_text = file_text[:5000] # Limit to 5000 chars for prompt size
|
457 |
query = f"{query}\n\n[Reference file content below]\n{file_text}"
|
458 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
# Enhance query with search if enabled
|
460 |
enhanced_query = enhance_query_with_search(query, enable_search)
|
461 |
|
@@ -478,7 +627,6 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
|
|
478 |
search_status = " (with web search)" if enable_search and tavily_client else ""
|
479 |
yield {
|
480 |
code_output: clean_code,
|
481 |
-
status_indicator: f'<div class="status-indicator generating" id="status">Generating code{search_status}...</div>',
|
482 |
history_output: history_to_chatbot_messages(_history),
|
483 |
}
|
484 |
_history = messages_to_history(messages + [{
|
@@ -489,19 +637,29 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
|
|
489 |
code_output: remove_code_block(content),
|
490 |
history: _history,
|
491 |
sandbox: send_to_sandbox(remove_code_block(content)),
|
492 |
-
status_indicator: '<div class="status-indicator success" id="status">Code generated successfully!</div>',
|
493 |
history_output: history_to_chatbot_messages(_history),
|
494 |
}
|
495 |
except Exception as e:
|
496 |
error_message = f"Error: {str(e)}"
|
497 |
yield {
|
498 |
code_output: error_message,
|
499 |
-
status_indicator: '<div class="status-indicator error" id="status">Error generating code</div>',
|
500 |
history_output: history_to_chatbot_messages(_history),
|
501 |
}
|
502 |
|
503 |
# Main application
|
504 |
-
with gr.Blocks(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
history = gr.State([])
|
506 |
setting = gr.State({
|
507 |
"system": SystemPrompt,
|
@@ -510,107 +668,125 @@ with gr.Blocks(theme=gr.themes.Base(), title="AnyCoder - AI Code Generator") as
|
|
510 |
open_panel = gr.State(None)
|
511 |
|
512 |
with gr.Sidebar():
|
513 |
-
gr.Markdown("# AnyCoder
|
514 |
-
gr.Markdown("
|
515 |
-
|
516 |
-
|
517 |
input = gr.Textbox(
|
518 |
-
label="
|
519 |
-
placeholder="
|
520 |
-
lines=
|
521 |
)
|
522 |
-
|
523 |
-
|
524 |
-
|
|
|
|
|
|
|
|
|
525 |
)
|
|
|
|
|
526 |
file_input = gr.File(
|
527 |
-
label="
|
528 |
file_types=[".pdf", ".txt", ".md", ".csv", ".docx", ".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif", ".gif", ".webp"],
|
529 |
visible=True
|
530 |
)
|
531 |
-
with gr.Row():
|
532 |
-
btn = gr.Button("Generate", variant="primary", size="sm")
|
533 |
-
clear_btn = gr.Button("Clear", variant="secondary", size="sm")
|
534 |
|
535 |
-
#
|
536 |
-
|
537 |
-
label="
|
538 |
-
|
539 |
-
info="Enable real-time web search to get the latest information and best practices"
|
540 |
)
|
541 |
|
542 |
-
#
|
543 |
-
|
544 |
-
gr.
|
545 |
-
|
546 |
-
gr.Markdown("✅ **Web Search Available**: Toggle above to enable real-time search")
|
547 |
|
548 |
-
|
|
|
|
|
|
|
|
|
549 |
|
550 |
-
|
551 |
-
for i, demo_item in enumerate(DEMO_LIST[:5]):
|
552 |
-
demo_card = gr.Button(
|
553 |
-
value=demo_item['title'],
|
554 |
-
variant="secondary",
|
555 |
-
size="sm"
|
556 |
-
)
|
557 |
-
demo_card.click(
|
558 |
-
fn=lambda idx=i: gr.update(value=DEMO_LIST[idx]['description']),
|
559 |
-
outputs=input
|
560 |
-
)
|
561 |
-
gr.Markdown("---")
|
562 |
model_dropdown = gr.Dropdown(
|
563 |
choices=[model['name'] for model in AVAILABLE_MODELS],
|
564 |
value=AVAILABLE_MODELS[0]['name'],
|
565 |
-
label="
|
566 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
567 |
def on_model_change(model_name):
|
568 |
for m in AVAILABLE_MODELS:
|
569 |
if m['name'] == model_name:
|
570 |
return m, f"**Model:** {m['name']}", update_image_input_visibility(m)
|
571 |
return AVAILABLE_MODELS[0], f"**Model:** {AVAILABLE_MODELS[0]['name']}", update_image_input_visibility(AVAILABLE_MODELS[0])
|
572 |
-
|
|
|
|
|
|
|
573 |
model_dropdown.change(
|
574 |
on_model_change,
|
575 |
inputs=model_dropdown,
|
576 |
outputs=[current_model, model_display, image_input]
|
577 |
)
|
578 |
-
|
|
|
|
|
579 |
systemPromptInput = gr.Textbox(
|
580 |
value=SystemPrompt,
|
581 |
-
label="System
|
582 |
-
lines=
|
583 |
)
|
584 |
-
save_prompt_btn = gr.Button("Save", variant="primary")
|
585 |
-
def save_prompt(input):
|
586 |
-
return {setting: {"system": input}}
|
587 |
save_prompt_btn.click(save_prompt, inputs=systemPromptInput, outputs=setting)
|
588 |
|
589 |
with gr.Column():
|
590 |
-
model_display
|
591 |
with gr.Tabs():
|
592 |
-
with gr.Tab("Code
|
593 |
code_output = gr.Code(
|
594 |
language="html",
|
595 |
lines=25,
|
596 |
interactive=False,
|
597 |
-
label="Generated
|
598 |
)
|
599 |
-
with gr.Tab("
|
600 |
-
sandbox = gr.HTML(label="Live
|
601 |
with gr.Tab("History"):
|
602 |
history_output = gr.Chatbot(show_label=False, height=400, type="messages")
|
603 |
-
|
604 |
-
'Ready to generate code',
|
605 |
-
)
|
606 |
|
607 |
# Event handlers
|
608 |
btn.click(
|
609 |
generation_code,
|
610 |
-
inputs=[input, image_input, file_input, setting, history, current_model, search_toggle],
|
611 |
-
outputs=[code_output, history, sandbox,
|
612 |
)
|
613 |
-
clear_btn.click(clear_history, outputs=[history, history_output, file_input])
|
614 |
|
615 |
if __name__ == "__main__":
|
616 |
demo.queue(default_concurrency_limit=20).launch(ssr_mode=True, mcp_server=True)
|
|
|
10 |
import numpy as np
|
11 |
from PIL import Image
|
12 |
import pytesseract
|
13 |
+
import requests
|
14 |
+
from urllib.parse import urlparse, urljoin
|
15 |
+
from bs4 import BeautifulSoup
|
16 |
+
import html2text
|
17 |
|
18 |
import gradio as gr
|
19 |
from huggingface_hub import InferenceClient
|
|
|
28 |
4. Include necessary comments and documentation
|
29 |
5. Ensure the code is functional and follows best practices
|
30 |
|
31 |
+
For website redesign tasks:
|
32 |
+
- Analyze the extracted website content to understand the structure and purpose
|
33 |
+
- Create a modern, responsive design that improves upon the original
|
34 |
+
- Maintain the core functionality and content while enhancing the user experience
|
35 |
+
- Use modern CSS frameworks and design patterns
|
36 |
+
- Ensure accessibility and mobile responsiveness
|
37 |
+
|
38 |
If an image is provided, analyze it and use the visual information to better understand the user's requirements.
|
39 |
|
40 |
Always respond with code that can be executed or rendered directly.
|
|
|
51 |
5. Include necessary comments and documentation
|
52 |
6. Ensure the code is functional and follows best practices
|
53 |
|
54 |
+
For website redesign tasks:
|
55 |
+
- Analyze the extracted website content to understand the structure and purpose
|
56 |
+
- Use web search to find current design trends and best practices for the specific type of website
|
57 |
+
- Create a modern, responsive design that improves upon the original
|
58 |
+
- Maintain the core functionality and content while enhancing the user experience
|
59 |
+
- Use modern CSS frameworks and design patterns
|
60 |
+
- Ensure accessibility and mobile responsiveness
|
61 |
+
|
62 |
If an image is provided, analyze it and use the visual information to better understand the user's requirements.
|
63 |
|
64 |
Always respond with code that can be executed or rendered directly.
|
|
|
143 |
{
|
144 |
"title": "Extract Text from Image",
|
145 |
"description": "Upload an image containing text and I'll extract and process the text content"
|
146 |
+
},
|
147 |
+
{
|
148 |
+
"title": "Website Redesign",
|
149 |
+
"description": "Enter a website URL to extract its content and redesign it with a modern, responsive layout"
|
150 |
}
|
151 |
]
|
152 |
|
|
|
241 |
return gr.update(visible=True), history
|
242 |
|
243 |
def clear_history():
|
244 |
+
return [], [], None, "" # Empty lists for both tuple format and chatbot messages, None for file, empty string for website URL
|
245 |
|
246 |
def update_image_input_visibility(model):
|
247 |
"""Update image input visibility based on selected model"""
|
|
|
461 |
except Exception as e:
|
462 |
return f"Error extracting text: {e}"
|
463 |
|
464 |
+
def extract_website_content(url: str) -> str:
|
465 |
+
"""Extract content from a website URL"""
|
466 |
+
try:
|
467 |
+
# Validate URL
|
468 |
+
parsed_url = urlparse(url)
|
469 |
+
if not parsed_url.scheme:
|
470 |
+
url = "https://" + url
|
471 |
+
parsed_url = urlparse(url)
|
472 |
+
|
473 |
+
if not parsed_url.netloc:
|
474 |
+
return "Error: Invalid URL provided"
|
475 |
+
|
476 |
+
# Set headers to mimic a browser request
|
477 |
+
headers = {
|
478 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
479 |
+
}
|
480 |
+
|
481 |
+
# Make the request
|
482 |
+
response = requests.get(url, headers=headers, timeout=10)
|
483 |
+
response.raise_for_status()
|
484 |
+
|
485 |
+
# Parse HTML content
|
486 |
+
soup = BeautifulSoup(response.content, 'html.parser')
|
487 |
+
|
488 |
+
# Remove script and style elements
|
489 |
+
for script in soup(["script", "style"]):
|
490 |
+
script.decompose()
|
491 |
+
|
492 |
+
# Extract title
|
493 |
+
title = soup.find('title')
|
494 |
+
title_text = title.get_text().strip() if title else "No title found"
|
495 |
+
|
496 |
+
# Extract meta description
|
497 |
+
meta_desc = soup.find('meta', attrs={'name': 'description'})
|
498 |
+
description = meta_desc.get('content', '') if meta_desc else ""
|
499 |
+
|
500 |
+
# Extract main content areas
|
501 |
+
content_sections = []
|
502 |
+
|
503 |
+
# Look for common content containers
|
504 |
+
main_selectors = [
|
505 |
+
'main', 'article', '.content', '.main-content', '.post-content',
|
506 |
+
'#content', '#main', '.entry-content', '.post-body'
|
507 |
+
]
|
508 |
+
|
509 |
+
for selector in main_selectors:
|
510 |
+
elements = soup.select(selector)
|
511 |
+
for element in elements:
|
512 |
+
text = element.get_text().strip()
|
513 |
+
if len(text) > 100: # Only include substantial content
|
514 |
+
content_sections.append(text)
|
515 |
+
|
516 |
+
# If no main content found, extract from body
|
517 |
+
if not content_sections:
|
518 |
+
body = soup.find('body')
|
519 |
+
if body:
|
520 |
+
# Remove navigation, footer, and other non-content elements
|
521 |
+
for element in body.find_all(['nav', 'footer', 'header', 'aside']):
|
522 |
+
element.decompose()
|
523 |
+
content_sections.append(body.get_text().strip())
|
524 |
+
|
525 |
+
# Extract navigation links
|
526 |
+
nav_links = []
|
527 |
+
nav_elements = soup.find_all(['nav', 'header'])
|
528 |
+
for nav in nav_elements:
|
529 |
+
links = nav.find_all('a')
|
530 |
+
for link in links:
|
531 |
+
link_text = link.get_text().strip()
|
532 |
+
link_href = link.get('href', '')
|
533 |
+
if link_text and link_href:
|
534 |
+
nav_links.append(f"{link_text}: {link_href}")
|
535 |
+
|
536 |
+
# Extract images
|
537 |
+
images = []
|
538 |
+
img_elements = soup.find_all('img')
|
539 |
+
for img in img_elements:
|
540 |
+
src = img.get('src', '')
|
541 |
+
alt = img.get('alt', '')
|
542 |
+
if src:
|
543 |
+
# Convert relative URLs to absolute
|
544 |
+
if not src.startswith(('http://', 'https://')):
|
545 |
+
src = urljoin(url, src)
|
546 |
+
images.append(f"Image: {alt} ({src})")
|
547 |
+
|
548 |
+
# Compile the extracted content
|
549 |
+
website_content = f"""
|
550 |
+
WEBSITE CONTENT EXTRACTION
|
551 |
+
==========================
|
552 |
+
|
553 |
+
URL: {url}
|
554 |
+
Title: {title_text}
|
555 |
+
Description: {description}
|
556 |
+
|
557 |
+
NAVIGATION MENU:
|
558 |
+
{chr(10).join(nav_links[:10]) if nav_links else "No navigation found"}
|
559 |
+
|
560 |
+
MAIN CONTENT:
|
561 |
+
{chr(10).join(content_sections[:3]) if content_sections else "No main content found"}
|
562 |
+
|
563 |
+
IMAGES:
|
564 |
+
{chr(10).join(images[:10]) if images else "No images found"}
|
565 |
+
|
566 |
+
PAGE STRUCTURE:
|
567 |
+
- This appears to be a {title_text.lower()} website
|
568 |
+
- Contains {len(content_sections)} main content sections
|
569 |
+
- Has {len(nav_links)} navigation links
|
570 |
+
- Includes {len(images)} images
|
571 |
+
"""
|
572 |
+
|
573 |
+
return website_content.strip()
|
574 |
+
|
575 |
+
except requests.exceptions.RequestException as e:
|
576 |
+
return f"Error accessing website: {str(e)}"
|
577 |
+
except Exception as e:
|
578 |
+
return f"Error extracting website content: {str(e)}"
|
579 |
+
|
580 |
+
def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optional[str], website_url: Optional[str], _setting: Dict[str, str], _history: Optional[History], _current_model: Dict, enable_search: bool = False):
|
581 |
if query is None:
|
582 |
query = ''
|
583 |
if _history is None:
|
|
|
595 |
file_text = file_text[:5000] # Limit to 5000 chars for prompt size
|
596 |
query = f"{query}\n\n[Reference file content below]\n{file_text}"
|
597 |
|
598 |
+
# Extract website content and append to query if website URL is present
|
599 |
+
website_text = ""
|
600 |
+
if website_url and website_url.strip():
|
601 |
+
website_text = extract_website_content(website_url.strip())
|
602 |
+
if website_text and not website_text.startswith("Error"):
|
603 |
+
website_text = website_text[:8000] # Limit to 8000 chars for prompt size
|
604 |
+
query = f"{query}\n\n[Website content to redesign below]\n{website_text}"
|
605 |
+
elif website_text.startswith("Error"):
|
606 |
+
query = f"{query}\n\n[Error extracting website: {website_text}]"
|
607 |
+
|
608 |
# Enhance query with search if enabled
|
609 |
enhanced_query = enhance_query_with_search(query, enable_search)
|
610 |
|
|
|
627 |
search_status = " (with web search)" if enable_search and tavily_client else ""
|
628 |
yield {
|
629 |
code_output: clean_code,
|
|
|
630 |
history_output: history_to_chatbot_messages(_history),
|
631 |
}
|
632 |
_history = messages_to_history(messages + [{
|
|
|
637 |
code_output: remove_code_block(content),
|
638 |
history: _history,
|
639 |
sandbox: send_to_sandbox(remove_code_block(content)),
|
|
|
640 |
history_output: history_to_chatbot_messages(_history),
|
641 |
}
|
642 |
except Exception as e:
|
643 |
error_message = f"Error: {str(e)}"
|
644 |
yield {
|
645 |
code_output: error_message,
|
|
|
646 |
history_output: history_to_chatbot_messages(_history),
|
647 |
}
|
648 |
|
649 |
# Main application
|
650 |
+
with gr.Blocks(
|
651 |
+
theme=gr.themes.Base(
|
652 |
+
primary_hue="blue",
|
653 |
+
secondary_hue="gray",
|
654 |
+
neutral_hue="gray",
|
655 |
+
font=gr.themes.GoogleFont("Inter"),
|
656 |
+
font_mono=gr.themes.GoogleFont("JetBrains Mono"),
|
657 |
+
text_size=gr.themes.sizes.text_md,
|
658 |
+
spacing_size=gr.themes.sizes.spacing_md,
|
659 |
+
radius_size=gr.themes.sizes.radius_md
|
660 |
+
),
|
661 |
+
title="AnyCoder - AI Code Generator"
|
662 |
+
) as demo:
|
663 |
history = gr.State([])
|
664 |
setting = gr.State({
|
665 |
"system": SystemPrompt,
|
|
|
668 |
open_panel = gr.State(None)
|
669 |
|
670 |
with gr.Sidebar():
|
671 |
+
gr.Markdown("# AnyCoder")
|
672 |
+
gr.Markdown("*AI-Powered Code Generator*")
|
673 |
+
|
674 |
+
# Main input section
|
675 |
input = gr.Textbox(
|
676 |
+
label="What would you like to build?",
|
677 |
+
placeholder="Describe your application...",
|
678 |
+
lines=3
|
679 |
)
|
680 |
+
|
681 |
+
# URL input for website redesign
|
682 |
+
website_url_input = gr.Textbox(
|
683 |
+
label="Website URL (for redesign)",
|
684 |
+
placeholder="https://example.com",
|
685 |
+
lines=1,
|
686 |
+
visible=True
|
687 |
)
|
688 |
+
|
689 |
+
# File upload (minimal)
|
690 |
file_input = gr.File(
|
691 |
+
label="Reference file",
|
692 |
file_types=[".pdf", ".txt", ".md", ".csv", ".docx", ".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif", ".gif", ".webp"],
|
693 |
visible=True
|
694 |
)
|
|
|
|
|
|
|
695 |
|
696 |
+
# Image input (only for ERNIE model)
|
697 |
+
image_input = gr.Image(
|
698 |
+
label="UI design image",
|
699 |
+
visible=False
|
|
|
700 |
)
|
701 |
|
702 |
+
# Action buttons
|
703 |
+
with gr.Row():
|
704 |
+
btn = gr.Button("Generate", variant="primary", size="lg", scale=2)
|
705 |
+
clear_btn = gr.Button("Clear", variant="secondary", size="sm", scale=1)
|
|
|
706 |
|
707 |
+
# Search toggle (minimal)
|
708 |
+
search_toggle = gr.Checkbox(
|
709 |
+
label="🔍 Web search",
|
710 |
+
value=False
|
711 |
+
)
|
712 |
|
713 |
+
# Model selection (minimal)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
714 |
model_dropdown = gr.Dropdown(
|
715 |
choices=[model['name'] for model in AVAILABLE_MODELS],
|
716 |
value=AVAILABLE_MODELS[0]['name'],
|
717 |
+
label="Model"
|
718 |
)
|
719 |
+
|
720 |
+
# Quick examples (minimal)
|
721 |
+
gr.Markdown("**Quick start**")
|
722 |
+
with gr.Column():
|
723 |
+
for i, demo_item in enumerate(DEMO_LIST[:3]):
|
724 |
+
demo_card = gr.Button(
|
725 |
+
value=demo_item['title'],
|
726 |
+
variant="secondary",
|
727 |
+
size="sm"
|
728 |
+
)
|
729 |
+
demo_card.click(
|
730 |
+
fn=lambda idx=i: gr.update(value=DEMO_LIST[idx]['description']),
|
731 |
+
outputs=input
|
732 |
+
)
|
733 |
+
|
734 |
+
# Status indicators (minimal)
|
735 |
+
if not tavily_client:
|
736 |
+
gr.Markdown("⚠️ Web search unavailable")
|
737 |
+
else:
|
738 |
+
gr.Markdown("✅ Web search available")
|
739 |
+
|
740 |
+
# Hidden elements for functionality
|
741 |
+
model_display = gr.Markdown(f"**Model:** {AVAILABLE_MODELS[0]['name']}", visible=False)
|
742 |
+
|
743 |
def on_model_change(model_name):
|
744 |
for m in AVAILABLE_MODELS:
|
745 |
if m['name'] == model_name:
|
746 |
return m, f"**Model:** {m['name']}", update_image_input_visibility(m)
|
747 |
return AVAILABLE_MODELS[0], f"**Model:** {AVAILABLE_MODELS[0]['name']}", update_image_input_visibility(AVAILABLE_MODELS[0])
|
748 |
+
|
749 |
+
def save_prompt(input):
|
750 |
+
return {setting: {"system": input}}
|
751 |
+
|
752 |
model_dropdown.change(
|
753 |
on_model_change,
|
754 |
inputs=model_dropdown,
|
755 |
outputs=[current_model, model_display, image_input]
|
756 |
)
|
757 |
+
|
758 |
+
# System prompt (collapsed by default)
|
759 |
+
with gr.Accordion("Advanced", open=False):
|
760 |
systemPromptInput = gr.Textbox(
|
761 |
value=SystemPrompt,
|
762 |
+
label="System prompt",
|
763 |
+
lines=5
|
764 |
)
|
765 |
+
save_prompt_btn = gr.Button("Save", variant="primary", size="sm")
|
|
|
|
|
766 |
save_prompt_btn.click(save_prompt, inputs=systemPromptInput, outputs=setting)
|
767 |
|
768 |
with gr.Column():
|
|
|
769 |
with gr.Tabs():
|
770 |
+
with gr.Tab("Code"):
|
771 |
code_output = gr.Code(
|
772 |
language="html",
|
773 |
lines=25,
|
774 |
interactive=False,
|
775 |
+
label="Generated code"
|
776 |
)
|
777 |
+
with gr.Tab("Preview"):
|
778 |
+
sandbox = gr.HTML(label="Live preview")
|
779 |
with gr.Tab("History"):
|
780 |
history_output = gr.Chatbot(show_label=False, height=400, type="messages")
|
781 |
+
|
|
|
|
|
782 |
|
783 |
# Event handlers
|
784 |
btn.click(
|
785 |
generation_code,
|
786 |
+
inputs=[input, image_input, file_input, website_url_input, setting, history, current_model, search_toggle],
|
787 |
+
outputs=[code_output, history, sandbox, history_output]
|
788 |
)
|
789 |
+
clear_btn.click(clear_history, outputs=[history, history_output, file_input, website_url_input])
|
790 |
|
791 |
if __name__ == "__main__":
|
792 |
demo.queue(default_concurrency_limit=20).launch(ssr_mode=True, mcp_server=True)
|
requirements.txt
CHANGED
@@ -5,4 +5,7 @@ PyPDF2
|
|
5 |
python-docx
|
6 |
pytesseract
|
7 |
Pillow
|
8 |
-
opencv-python
|
|
|
|
|
|
|
|
5 |
python-docx
|
6 |
pytesseract
|
7 |
Pillow
|
8 |
+
opencv-python
|
9 |
+
requests
|
10 |
+
beautifulsoup4
|
11 |
+
html2text
|