from tkinter import Label import gradio as gr import logging 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 code_kit.agent_code_generator import code_generation_agent from code_kit.agent_style_generator import generate_random_style from code_kit.code_examples import CODE_EXAMPLES # Configure logging logger = logging.getLogger(__name__) def refresh_preview(code_type_display_name, current_code, chatbot_history): """ Refresh the preview and add a log entry. Refactored to rely solely on the HTML content for preview, assuming all frameworks produce a single-file HTML output that works in an iframe. """ logger.info(f"--- [Manual Refresh] Start ---") logger.info(f"Code Type: {code_type_display_name}") # Simple validation: Check if code seems to be HTML if not current_code or not isinstance(current_code, str): chatbot_history.append({"role": "assistant", "content": "⚠️ **警告**: 没有代码可供刷新。"}) return gr.update(), chatbot_history # For all currently supported frameworks (Static, React+Tailwind, R3F, Old School), # the output is a self-contained HTML string. # So we can process them uniformly. escaped_code = current_code.replace("'", "'").replace('"', '"') final_preview_html = f"""
""" chatbot_history.append({"role": "assistant", "content": "🔄 **状态**: 预览已手动刷新。"}) logger.info("Refreshed preview.") return gr.HTML(final_preview_html), 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(): # Inject custom CSS to hide components gr.HTML(""" """) fullscreen_state = gr.State(False) 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="提示词") overall_style_input = gr.Textbox(label="整体风格", placeholder="例如:类似一本羊皮纸的书", lines=2) decoration_input = gr.Textbox(label="装饰风格", placeholder="例如:粗边框,无圆角", lines=2) # Hidden textbox to store the raw palette string for the prompt palette_input = gr.Textbox(label="Palette (Raw)", elem_classes="hidden-component") palette_display = gr.HTML(value='预览将在此处显示。
") 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) js_error_channel = gr.Textbox(visible=True, elem_classes=["js_error_channel"], label="Debug Error Channel", interactive=False) # Event Handler for Example Selection def on_select_example(evt: gr.SelectData): selected_task = evt.value[0] item = next((i for i in CODE_EXAMPLES if i["task"] == selected_task), None) if not item: return gr.update(), gr.update() return gr.update(value=item["user_prompt"]), gr.update(value=item["model"]) examples_dataset.select( fn=on_select_example, inputs=None, outputs=[prompt_input, model_choice_dropdown], show_progress="none" ) # Event Handler for Style Generation generate_style_btn.click( fn=generate_random_style, inputs=[model_choice_dropdown], outputs=[palette_display, palette_input, decoration_input, overall_style_input] ) refresh_button.click( fn=refresh_preview, inputs=[code_framework_dropdown, code_output, log_chatbot], outputs=[preview_output, log_chatbot] ) generate_button.click( fn=code_generation_agent, inputs=[ code_framework_dropdown, model_choice_dropdown, prompt_input, palette_input, # Pass the raw palette string decoration_input, overall_style_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 )