"""Тестовая страница: та же логика прикрепления .zip с XML, что и в проде (main.py), но с ручным вводом username/App Token вместо Keycloak-сессии — чтобы гонять всю цепочку (парсинг + загрузка в OpenCloud) локально, без поднятого raisa_streamlit_oauth. Запуск: streamlit run scripts/local_zip_test_app.py Username/токен можно один раз прописать в .env (см. .env.example) — поля на странице предзаполнятся, но их всегда можно поменять руками. Личное пространство ищется автоматически через GET /graph/v1.0/me/drives, см. app/opencloud_access.py. """ from __future__ import annotations import os import sys import tempfile from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) import streamlit as st from dotenv import load_dotenv from app.pipeline.service import run_batch load_dotenv() st.set_page_config(page_title="СФМ — локальный тест", page_icon="📦") st.title("Локальный тест: zip → обработка → OpenCloud") st.caption( "Прикрепляете .zip с XML-файлами, он распаковывается и обрабатывается " "тем же кодом парсинга, что и прод (app/pipeline/parser.py), а отчёт, " "протокол и лог грузятся в OpenCloud (app/opencloud_access.py). Та же " "логика, что и в main.py, только username/token вводятся руками." ) username = st.text_input( "Username (для Basic Auth в OpenCloud)", value=os.getenv("SFM_OPENCLOUD_USERNAME", ""), help="Логин, под которым заказчик создал App Token в OpenCloud. Можно прописать в .env как SFM_OPENCLOUD_USERNAME.", ) access_token = st.text_input( "App Token", value=os.getenv("SFM_OPENCLOUD_ACCESS_TOKEN", ""), type="password", help=( "Долгоживущий App Token из веб-интерфейса OpenCloud (не Bearer из Keycloak — " "авторизация теперь через HTTP Basic Auth). Можно прописать в .env как " "SFM_OPENCLOUD_ACCESS_TOKEN." ), ) launcher = st.text_input("Запустил (для протокола)", value="local-test") uploaded_zip = st.file_uploader("Архив с XML-файлами (.zip)", type=["zip"]) if st.button("Начать обработку", type="primary", use_container_width=True): if not username: st.error("Укажите username.") elif not access_token: st.error("Укажите App Token.") elif uploaded_zip is None: st.error("Прикрепите .zip-архив.") else: with tempfile.TemporaryDirectory() as tmp_dir: zip_path = Path(tmp_dir) / uploaded_zip.name zip_path.write_bytes(uploaded_zip.getvalue()) with st.spinner("Распаковываем, обрабатываем, грузим в OpenCloud..."): result = run_batch( zip_path=zip_path, launcher=launcher or "local-test", opencloud_username=username, opencloud_access_token=access_token, ) if result.status == "success": st.success("Обработка завершена успешно.") elif result.status == "partial": st.warning("Обработка завершена частично.") else: st.error("Обработка завершена с ошибками.") st.write( { "processed": result.processed, "partial": result.partial, "errors": result.errors, "report_path": result.report_path, "protocol_path": result.protocol_path, "log_path": result.log_path, "duration_seconds": result.duration_seconds, } ) if result.messages: st.caption("Сообщения обработки:") for message in result.messages: st.write(f"- {message}")