diff --git a/frontend/ui.py b/frontend/ui.py index ba111d9..de10ec9 100644 --- a/frontend/ui.py +++ b/frontend/ui.py @@ -3,12 +3,11 @@ from datetime import datetime, timezone import requests import streamlit as st -import yaml st.set_page_config(page_title="DevOps AI Assistant", page_icon="🚀") st.title("DevOps AI Assistant") -st.markdown("Веб-интерфейс для генерации и проверки CI/CD конфигураций.") +st.markdown("Портал с данными и инструментами для АС/ФП.") def _env(name: str, default: str) -> str: @@ -38,6 +37,13 @@ if "history" not in st.session_state: st.session_state.history = [] if "token" not in st.session_state: st.session_state.token = None +if "asfp_info" not in st.session_state: + st.session_state.asfp_info = { + "name": "", + "owner": "", + "contacts": "", + "description": "", + } def _push_history(*, platform: str, model: str, prompt: str, status: str, config: str, error: str | None): @@ -140,27 +146,41 @@ if not st.session_state.token: st.stop() -tab_overview, tab_account, tab_generator, tab_validator, tab_history = st.tabs( - ["Обзор", "Аккаунт", "Pipeline generator", "Проверка YAML", "История"] +tab_info, tab_autonomous, tab_infra, tab_tools, tab_news = st.tabs( + [ + "Сведения об АС/ФП", + "Автономные внедрения", + "Инфраструктура АС/ФП", + "Инструменты", + "Новости", + ] ) -with tab_overview: - st.subheader("Что умеет сервис") - st.markdown( - "- **Pipeline generator**: генерирует YAML через backend (FastAPI → Ollama).\n" - "- **Проверка YAML**: локально проверяет синтаксис YAML, чтобы быстро править конфиг.\n" - "- **История**: хранит последние результаты в рамках сессии браузера." +with tab_info: + st.subheader("Сведения об АС/ФП") + st.caption("Черновик формы. Дальше можно привязать к Postgres и хранить как сущность.") + st.session_state.asfp_info["name"] = st.text_input("Название", st.session_state.asfp_info["name"]) + st.session_state.asfp_info["owner"] = st.text_input("Владелец", st.session_state.asfp_info["owner"]) + st.session_state.asfp_info["contacts"] = st.text_input("Контакты", st.session_state.asfp_info["contacts"]) + st.session_state.asfp_info["description"] = st.text_area( + "Описание", st.session_state.asfp_info["description"], height=120 ) st.divider() + st.json(st.session_state.asfp_info) + +with tab_autonomous: + st.subheader("Автономные внедрения") + st.info("Сюда можно добавить список внедрений, статус, даты, ответственных и ссылки на релизы/тикеты.") + +with tab_infra: + st.subheader("Инфраструктура АС/ФП") + st.info("Сюда можно добавить окружения, кластера, сервисы, ресурсы, сетевые зависимости, секреты и т.д.") + +with tab_tools: + st.subheader("Инструменты") st.caption(f"Backend URL: {backend_base_url}") - st.success("Вы вошли в систему.") - -with tab_account: - _show_account() - -with tab_generator: - st.subheader("AI CI/CD Pipeline Generator") + st.markdown("### Pipeline generator") user_input = st.text_area( "Опишите пайплайн (например: 'Python app with pytest and docker build')", height=150, @@ -169,16 +189,9 @@ with tab_generator: col_a, col_b = st.columns([1, 3]) with col_a: - generate_clicked = st.button( - "Сгенерировать конфигурацию", - type="primary", - disabled=not bool(st.session_state.token), - ) + generate_clicked = st.button("Сгенерировать конфигурацию", type="primary") with col_b: - if st.session_state.token: - st.caption("Подсказка: чем конкретнее требования, тем валиднее YAML.") - else: - st.warning("Нужно войти во вкладке «Аккаунт», чтобы генерировать.") + st.caption("Подсказка: чем конкретнее требования, тем валиднее YAML.") if generate_clicked: if user_input.strip(): @@ -218,48 +231,6 @@ with tab_generator: else: st.warning("Пожалуйста, введите описание.") -with tab_validator: - st.subheader("Локальная проверка YAML") - yaml_text = st.text_area("Вставьте YAML для проверки", height=240, key="validator_yaml") - - c1, c2 = st.columns([1, 1]) - with c1: - validate_clicked = st.button("Проверить YAML") - with c2: - if st.button("Вставить последний результат", disabled=(len(st.session_state.history) == 0)): - st.session_state.validator_yaml = (st.session_state.history[0].get("config") or "") - st.rerun() - - if validate_clicked: - if yaml_text.strip(): - try: - yaml.safe_load(yaml_text) - st.success("YAML синтаксически валиден.") - except Exception as e: - st.error(f"Ошибка YAML: {e}") - else: - st.warning("Вставьте YAML.") - -with tab_history: - st.subheader("История (последние 50)") - - if not st.session_state.history: - st.info("Пока пусто. Сгенерируйте конфигурацию во вкладке Pipeline generator.") - else: - if st.button("Очистить историю"): - st.session_state.history = [] - st.rerun() - - for idx, item in enumerate(st.session_state.history): - title = f"[{item['ts']}] {item['platform']} · {item['model']} · {item['status']}" - with st.expander(title, expanded=(idx == 0)): - st.caption(item.get("prompt", "")) - if item.get("error"): - st.error(f"Validation error: {item['error']}") - st.code(item.get("config", ""), language="yaml") - st.download_button( - "Скачать .yml", - item.get("config", ""), - file_name=f"pipeline-{idx+1}.yml", - key=f"download_{idx}", - ) +with tab_news: + st.subheader("Новости") + st.info("Сюда можно вывести новости/изменения: релизы, инциденты, регламентные работы, обновления инструментов.")