Spaces:
Running
Running
File size: 10,931 Bytes
b931367 74ebe5c b931367 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
import gradio as gr
import time
import logging
from model_handler import ModelHandler
from config import CHAT_MODEL_SPECS, LING_1T, CODE_FRAMEWORK_SPECS, STATIC_PAGE
from ui_components.model_selector import create_model_selector
from ui_components.code_framework_selector import create_code_framework_selector
from tab_code_prompts.html_system_prompt import get_html_system_prompt
# Configure logging
logger = logging.getLogger(__name__)
# Read the content of the JavaScript file for error catching
try:
with open("static/catch-error.js", "r", encoding="utf-8") as f:
CATCH_ERROR_JS_SCRIPT = f.read()
except FileNotFoundError:
logger.error("Error: static/catch-error.js not found. The error catching overlay will not work.")
CATCH_ERROR_JS_SCRIPT = ""
def get_spinner_html():
"""Return HTML with a CSS spinner animation"""
return """
<div style="width: 100%; height: 600px; display: flex; justify-content: center; align-items: center; border: 1px solid #ddd; background-color: #f9f9f9;">
<div class="spinner"></div>
</div>
<style>
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
width: 36px;
height: 36px;
border-radius: 50%;
border-left-color: #09f;
animation: spin 1s ease infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
"""
def generate_code(code_type, model_choice, user_prompt, chatbot_history):
"""Generate code and provide a preview, updating a log stream chatbot."""
logger.info(f"--- [Code Generation] Start ---")
logger.info(f"Code Type: {code_type}, Model: {model_choice}, Prompt: '{user_prompt}'")
if not user_prompt:
chatbot_history.append({"role": "assistant", "content": "🚨 **错误**: 请输入提示词。"})
yield "", gr.update(value="<p>预览将在此处显示。</p>"), chatbot_history, gr.update()
return
chatbot_history.append({"role": "assistant", "content": "⏳ 开始生成代码..."})
yield "", gr.HTML(get_spinner_html()), chatbot_history, gr.update()
if user_prompt == "create an error":
error_code = f"""<h1>This will create an error</h1><script>{CATCH_ERROR_JS_SCRIPT}</script><script>nonExistentFunction();</script>""";
escaped_code = error_code.replace("'", "'").replace('"', '"')
final_preview_html = f"""
<div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
<iframe srcdoc='{escaped_code}'
style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
</iframe>
</div>
"""
chatbot_history.append({"role": "assistant", "content": "✅ **成功**: 已生成一个用于测试的错误页面。"})
yield error_code, gr.update(value=final_preview_html), chatbot_history, gr.Tabs(selected=0)
return
start_time = time.time()
model_handler = ModelHandler()
if code_type == "静态页面":
system_prompt = get_html_system_prompt()
full_code_with_think = ""
full_code_for_preview = ""
buffer = ""
is_thinking = False
for code_chunk in model_handler.generate_code(system_prompt, user_prompt, model_choice):
full_code_with_think += code_chunk
buffer += code_chunk
while True:
if is_thinking:
end_index = buffer.find("</think>")
if end_index != -1:
is_thinking = False
buffer = buffer[end_index + len("</think>"):]
else:
break
else:
start_index = buffer.find("<think>")
if start_index != -1:
part_to_add = buffer[:start_index]
full_code_for_preview += part_to_add
is_thinking = True
buffer = buffer[start_index:]
else:
full_code_for_preview += buffer
buffer = ""
break
elapsed_time = time.time() - start_time
generated_length = len(full_code_with_think)
speed = generated_length / elapsed_time if elapsed_time > 0 else 0
log_message = f"""
**⏳ 正在生成中...**
- **时间:** {elapsed_time:.2f}s
- **长度:** {generated_length} chars
- **速度:** {speed:.2f} char/s
"""
if len(chatbot_history) > 0 and "正在生成中" in chatbot_history[-1]["content"]:
chatbot_history[-1] = {"role": "assistant", "content": log_message}
else:
chatbot_history.append({"role": "assistant", "content": log_message})
yield full_code_with_think, gr.update(), chatbot_history, gr.update()
escaped_code = full_code_for_preview.replace("'", "'").replace('"', '"')
final_preview_html = f"""
<div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
<iframe srcdoc='{escaped_code}'
style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
</iframe>
</div>
"""
chatbot_history.append({"role": "assistant", "content": "✅ **成功**: 代码生成完成!"})
yield full_code_with_think, gr.HTML(final_preview_html), chatbot_history, gr.Tabs(selected=0)
logger.info("Static page streaming finished.")
def refresh_preview(code_type, current_code, chatbot_history):
"""Refresh the preview and add a log entry."""
logger.info(f"--- [Manual Refresh] Start ---")
logger.info(f"Code Type: {code_type}")
if code_type == "静态页面":
escaped_code = current_code.replace("'", "'").replace('"', '"')
final_preview_html = f"""
<div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
<iframe srcdoc='{escaped_code}'
style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
</iframe>
</div>
"""
chatbot_history.append({"role": "assistant", "content": "🔄 **状态**: 预览已手动刷新。"})
logger.info("Refreshed static page preview.")
return gr.HTML(final_preview_html), chatbot_history
chatbot_history.append({"role": "assistant", "content": "⚠️ **警告**: 未知的代码类型,无法刷新。"})
return gr.update(), chatbot_history
def toggle_fullscreen(is_fullscreen):
is_fullscreen = not is_fullscreen
new_button_text = "退出全屏" if is_fullscreen else "全屏预览"
panel_visibility = not is_fullscreen
return is_fullscreen, gr.update(value=new_button_text), gr.update(visible=panel_visibility)
def log_js_error(error_text, chatbot_history):
"""Appends a JavaScript error received from the frontend to the log chatbot."""
if not error_text:
return chatbot_history
formatted_error = f"🚨 **在预览中发现运行时异常!**\n```\n{error_text}\n```"
# Check if the last message is the same error to prevent flooding
if chatbot_history and chatbot_history[-1]["content"] == formatted_error:
return chatbot_history
chatbot_history.append({"role": "assistant", "content": formatted_error})
return chatbot_history
def create_code_tab():
fullscreen_state = gr.State(False)
html_examples = [
"Write a hello world alert",
"Create a Canvas animation of continuous colorful fireworks blooming on a black background.",
"Generate a Canvas special effect with iridescent light streams.",
"create an error"
]
with gr.Row(elem_id="indicator-code-tab"):
with gr.Column(scale=1) as left_panel:
with gr.Column(scale=1): # Settings Panel
code_framework_dropdown = create_code_framework_selector(
framework_specs=CODE_FRAMEWORK_SPECS,
default_framework_constant=STATIC_PAGE
)
model_choice_dropdown, model_description_markdown = create_model_selector(
model_specs=CHAT_MODEL_SPECS,
default_model_constant=LING_1T
)
prompt_input = gr.Textbox(lines=5, placeholder="例如:创建一个带标题和按钮的简单页面", label="提示词")
with gr.Column():
gr.Examples(examples=html_examples, inputs=prompt_input, label="✨ 试试这些酷炫的例子吧")
generate_button = gr.Button("生成代码", variant="primary")
with gr.Column(scale=4):
with gr.Tabs(elem_id="result_tabs") as result_tabs:
with gr.TabItem("实时预览", id=0):
with gr.Row():
gr.Markdown("### 实时预览")
fullscreen_button = gr.Button("全屏预览", scale=0)
preview_output = gr.HTML(value="<p>预览将在此处显示。</p>")
with gr.TabItem("生成的源代码", id=1):
gr.Markdown("### 生成的源代码")
code_output = gr.Code(language="html", label="生成的代码", interactive=True)
refresh_button = gr.Button("刷新预览")
with gr.Column(scale=1):
log_chatbot = gr.Chatbot(label="生成日志", height=300, type="messages")
js_error_channel = gr.Textbox(visible=True, elem_classes=["js_error_channel"], label="Debug Error Channel", interactive=False)
refresh_button.click(
fn=refresh_preview,
inputs=[code_framework_dropdown, code_output, log_chatbot],
outputs=[preview_output, log_chatbot]
)
generate_button.click(
fn=generate_code,
inputs=[code_framework_dropdown, model_choice_dropdown, prompt_input, log_chatbot],
outputs=[code_output, preview_output, log_chatbot, result_tabs]
)
fullscreen_button.click(
fn=toggle_fullscreen,
inputs=[fullscreen_state],
outputs=[fullscreen_state, fullscreen_button, left_panel]
)
js_error_channel.change(
fn=log_js_error,
inputs=[js_error_channel, log_chatbot],
outputs=log_chatbot
)
|