# src/ui/layout.py """ Модуль верстки пользовательского интерфейса Gradio. ИСПРАВЛЕНО: Удалена тема Soft для возврата стандартных шрифтов. ДОБАВЛЕНО: Компоненты для просмотра 2D SVG-плана и скачивания JSON-артефактов. """ import gradio as gr from omegaconf import DictConfig from .callbacks import ( generate_wrapper, get_cache_status_text, get_inventory_json ) def create_ui(cfg: DictConfig) -> gr.Blocks: """ Создает структуру веб-интерфейса. """ with gr.Blocks(title="ИИ-Мерчандайзер 3D") as app: gr.Markdown("# 🏪 Интеллектуальный генератор 3D-планировок") # 1. Текстовое табло с общей статистикой server_status = gr.Textbox( value=get_cache_status_text, label="Статус сервера и общая статистика", interactive=False, lines=2 ) # 2. Инспектор ассортимента (под аккордеоном) with gr.Accordion("📦 Детальный просмотр доступных SKU", open=False): inventory_inspect = gr.JSON( value=get_inventory_json, label="Иерархия товаров в ОЗУ" ) # 3. Панель управления with gr.Row(): prompt_input = gr.Textbox( label="✨ Текстовый запрос к ИИ-мерчандайзеру", placeholder="Например: Поставь молоко в холодильник, а пиво на стеллаж напротив.", lines=2, scale=4 ) generate_btn = gr.Button("🚀 Сгенерировать", variant="primary", scale=1) # 4. Область вывода результатов генерации with gr.Row(): with gr.Column(scale=1): status_output = gr.Textbox( label="Чек-лист выполнения", value="🟢 Ожидание запуска...", interactive=False, lines=15 ) with gr.Column(scale=3): # Вкладки для переключения между 3D и 2D with gr.Tabs(): with gr.TabItem("🎮 3D Сцена"): output_3d = gr.Model3D( label="Результат 3D-рендера", clear_color=[0.9, 0.9, 0.9, 1.0], height=600 ) with gr.TabItem("🗺️ 2D План (SVG)"): output_svg = gr.Image( label="Векторный план расстановки", type="filepath", interactive=False ) # 5. Панель артефактов (для скачивания) with gr.Row(): draft_json_out = gr.File(label="📥 Скачать черновик LLM (Draft JSON)") final_json_out = gr.File(label="📥 Скачать финальный расчет (Final JSON)") history_json_out = gr.File(label="📥 Скачать историю LLM (JSONL)") draft_svg_file_out = gr.File(label="📥 Draft SVG") svg_file_out = gr.File(label="📥 Скачать 2D План (SVG)") # Привязка событий: теперь функция должна возвращать 5 значений (3D, Чеклист, SVG-превью, Draft, Final, SVG-файл) # Так как SVG-файл и SVG-превью - это один и тот же файл, мы просто передадим его путь дважды в outputs generate_btn.click( fn=generate_wrapper, inputs=[prompt_input], outputs=[ output_3d, status_output, output_svg, draft_json_out, final_json_out, svg_file_out, history_json_out, draft_svg_file_out ], show_progress="hidden" ) return app