From f16ab7133a2f5999073d251ce65e31d848310934 Mon Sep 17 00:00:00 2001 From: Maksim Date: Thu, 28 Aug 2025 12:16:36 +0300 Subject: [PATCH] runs --- python_parser/.streamlit/config.toml | 28 ++ python_parser/Dockerfile | 25 +- python_parser/QUICK_START.md | 66 +++ python_parser/README.md | 197 +++++++++ python_parser/README_STREAMLIT.md | 186 ++++++++ .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 172 bytes .../__pycache__/pconfig.cpython-313.pyc | Bin 0 -> 8206 bytes .../__pycache__/storage.cpython-313.pyc | Bin 0 -> 7366 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 382 bytes .../monitoring_fuel.cpython-313.pyc | Bin 0 -> 9730 bytes .../__pycache__/svodka_ca.cpython-313.pyc | Bin 0 -> 14638 bytes .../__pycache__/svodka_pm.cpython-313.pyc | Bin 0 -> 12754 bytes python_parser/adapters/storage.py | 82 +++- .../app/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 167 bytes .../app/__pycache__/main.cpython-313.pyc | Bin 0 -> 18405 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 615 bytes .../monitoring_fuel.cpython-313.pyc | Bin 0 -> 1690 bytes .../__pycache__/server.cpython-313.pyc | Bin 0 -> 1401 bytes .../__pycache__/svodka_ca.cpython-313.pyc | Bin 0 -> 1635 bytes .../__pycache__/svodka_pm.cpython-313.pyc | Bin 0 -> 3122 bytes .../__pycache__/upload.cpython-313.pyc | Bin 0 -> 2611 bytes python_parser/check_services.py | 185 ++++++++ .../core/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 168 bytes .../core/__pycache__/models.cpython-313.pyc | Bin 0 -> 2536 bytes .../core/__pycache__/ports.cpython-313.pyc | Bin 0 -> 2572 bytes .../core/__pycache__/services.cpython-313.pyc | Bin 0 -> 5502 bytes python_parser/core/services.py | 8 +- python_parser/docker-compose.yml | 32 +- .../buckets/.bloomcycle.bin/xl.meta | Bin 743 -> 743 bytes .../.minio.sys/buckets/.heal/mrf/list.bin | Bin 0 -> 4 bytes .../buckets/.usage-cache.bin.bkp/xl.meta | Bin 633 -> 623 bytes .../buckets/.usage-cache.bin/xl.meta | Bin 633 -> 623 bytes .../.minio.sys/buckets/.usage.json/xl.meta | Bin 1505 -> 1505 bytes .../svodka-data/.usage-cache.bin.bkp/xl.meta | Bin 716 -> 701 bytes .../svodka-data/.usage-cache.bin/xl.meta | Bin 716 -> 701 bytes .../identity.json/xl.meta | Bin 0 -> 910 bytes .../identity.json/xl.meta | Bin 910 -> 0 bytes .../xl.meta.bkp | Bin 743 -> 0 bytes .../xl.meta.bkp | Bin 633 -> 0 bytes .../xl.meta.bkp | Bin 702 -> 0 bytes .../xl.meta.bkp | Bin 702 -> 0 bytes .../xl.meta.bkp | Bin 1505 -> 0 bytes .../xl.meta.bkp | Bin 633 -> 0 bytes ...8 => 060ca61d-ef6c-4011-9a9f-d083313258e8} | Bin python_parser/requirements.txt | 3 +- python_parser/run_dev.py | 2 +- python_parser/run_streamlit.py | 51 +++ python_parser/streamlit_app.py | 402 ++++++++++++++++++ 48 files changed, 1221 insertions(+), 46 deletions(-) create mode 100644 python_parser/.streamlit/config.toml create mode 100644 python_parser/QUICK_START.md create mode 100644 python_parser/README.md create mode 100644 python_parser/README_STREAMLIT.md create mode 100644 python_parser/adapters/__pycache__/__init__.cpython-313.pyc create mode 100644 python_parser/adapters/__pycache__/pconfig.cpython-313.pyc create mode 100644 python_parser/adapters/__pycache__/storage.cpython-313.pyc create mode 100644 python_parser/adapters/parsers/__pycache__/__init__.cpython-313.pyc create mode 100644 python_parser/adapters/parsers/__pycache__/monitoring_fuel.cpython-313.pyc create mode 100644 python_parser/adapters/parsers/__pycache__/svodka_ca.cpython-313.pyc create mode 100644 python_parser/adapters/parsers/__pycache__/svodka_pm.cpython-313.pyc create mode 100644 python_parser/app/__pycache__/__init__.cpython-313.pyc create mode 100644 python_parser/app/__pycache__/main.cpython-313.pyc create mode 100644 python_parser/app/schemas/__pycache__/__init__.cpython-313.pyc create mode 100644 python_parser/app/schemas/__pycache__/monitoring_fuel.cpython-313.pyc create mode 100644 python_parser/app/schemas/__pycache__/server.cpython-313.pyc create mode 100644 python_parser/app/schemas/__pycache__/svodka_ca.cpython-313.pyc create mode 100644 python_parser/app/schemas/__pycache__/svodka_pm.cpython-313.pyc create mode 100644 python_parser/app/schemas/__pycache__/upload.cpython-313.pyc create mode 100644 python_parser/check_services.py create mode 100644 python_parser/core/__pycache__/__init__.cpython-313.pyc create mode 100644 python_parser/core/__pycache__/models.cpython-313.pyc create mode 100644 python_parser/core/__pycache__/ports.cpython-313.pyc create mode 100644 python_parser/core/__pycache__/services.cpython-313.pyc create mode 100644 python_parser/minio/.minio.sys/buckets/.heal/mrf/list.bin create mode 100644 python_parser/minio/.minio.sys/config/iam/sts/46KX4VILT0DATJ36SYGD/identity.json/xl.meta delete mode 100644 python_parser/minio/.minio.sys/config/iam/sts/SIXCOIEK8M17XZ3JTN2B/identity.json/xl.meta delete mode 100644 python_parser/minio/.minio.sys/tmp/.trash/47c67d1c-8a41-4ea8-8a29-09319e725c00/xl.meta.bkp delete mode 100644 python_parser/minio/.minio.sys/tmp/.trash/86b41a62-b469-455b-be17-9d44996ebdd3/xl.meta.bkp delete mode 100644 python_parser/minio/.minio.sys/tmp/.trash/aa8293d8-dcc1-4475-8490-1c6a8e9f19ad/xl.meta.bkp delete mode 100644 python_parser/minio/.minio.sys/tmp/.trash/d7b1a3d7-340d-468e-86cf-1a4321c26dbf/xl.meta.bkp delete mode 100644 python_parser/minio/.minio.sys/tmp/.trash/ee3a854e-91ed-4a7c-ab72-f2df6ae6337a/xl.meta.bkp delete mode 100644 python_parser/minio/.minio.sys/tmp/.trash/f3730b42-e1d0-4653-b974-5938ec8af694/xl.meta.bkp rename python_parser/minio/.minio.sys/tmp/{989d8b07-b593-41fc-9dbf-831f9b04f598 => 060ca61d-ef6c-4011-9a9f-d083313258e8} (100%) create mode 100644 python_parser/run_streamlit.py create mode 100644 python_parser/streamlit_app.py diff --git a/python_parser/.streamlit/config.toml b/python_parser/.streamlit/config.toml new file mode 100644 index 0000000..84e0551 --- /dev/null +++ b/python_parser/.streamlit/config.toml @@ -0,0 +1,28 @@ +[server] +port = 8501 +address = "localhost" +headless = false +enableCORS = false +enableXsrfProtection = false + +[browser] +gatherUsageStats = false +serverAddress = "localhost" +serverPort = 8501 + +[theme] +primaryColor = "#FF4B4B" +backgroundColor = "#FFFFFF" +secondaryBackgroundColor = "#F0F2F6" +textColor = "#262730" +font = "sans serif" + +[client] +showErrorDetails = true +caching = true +displayEnabled = true + +[runner] +magicEnabled = true +installTracer = false +fixMatplotlib = true \ No newline at end of file diff --git a/python_parser/Dockerfile b/python_parser/Dockerfile index d1409f7..51216a8 100644 --- a/python_parser/Dockerfile +++ b/python_parser/Dockerfile @@ -1,20 +1,23 @@ -FROM repo-dev.predix.rosneft.ru/python:3.11-slim +FROM python:3.11-slim WORKDIR /app -# RUN pip install kafka-python==2.0.2 -# RUN pip freeze > /app/requirements.txt +# Устанавливаем системные зависимости +RUN apt-get update && apt-get install -y \ + gcc \ + && rm -rf /var/lib/apt/lists/* -# ADD . /app +# Копируем файлы зависимостей COPY requirements.txt . -RUN mkdir -p vendor -RUN pip download -r /app/requirements.txt --no-binary=:none: -d /app/vendor +# Устанавливаем Python зависимости +RUN pip install --no-cache-dir -r requirements.txt -# ADD . /app +# Копируем код приложения +COPY . . -# ENV KAFKA_BROKER=10.234.160.10:9093,10.234.160.10:9094,10.234.160.10:9095 -# ENV KAFKA_UPDATE_ALGORITHM_RULES_TOPIC=algorithm-rule-update -# ENV KAFKA_CLIENT_USERNAME=cf-service +# Открываем порт +EXPOSE 8000 -# CMD ["python", "/app/run_dev.py"] \ No newline at end of file +# Команда запуска +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/python_parser/QUICK_START.md b/python_parser/QUICK_START.md new file mode 100644 index 0000000..d81b67f --- /dev/null +++ b/python_parser/QUICK_START.md @@ -0,0 +1,66 @@ +# 🚀 Быстрый старт NIN Excel Parsers API + +## 🐳 Запуск через Docker (рекомендуется) + +### Вариант 1: MinIO + FastAPI в Docker +```bash +# Запуск всех сервисов +docker-compose up -d --build + +# Проверка +curl http://localhost:8000 +curl http://localhost:9001 +``` + +### Вариант 2: Только MinIO в Docker +```bash +# Запуск только MinIO +docker-compose up -d minio + +# Проверка +curl http://localhost:9001 +``` + +## 🖥️ Запуск FastAPI локально + +```bash +# Если MinIO в Docker +python run_dev.py + +# Проверка +curl http://localhost:8000 +``` + +## 📊 Запуск Streamlit + +```bash +# В отдельном терминале +python run_streamlit.py +``` + +## 🌐 Доступные URL + +- **FastAPI API**: http://localhost:8000 +- **API документация**: http://localhost:8000/docs +- **MinIO консоль**: http://localhost:9001 +- **Streamlit интерфейс**: http://localhost:8501 + +## 🛑 Остановка + +```bash +# Остановка Docker +docker-compose down + +# Остановка Streamlit +# Ctrl+C в терминале +``` + +## 🔧 Диагностика + +```bash +# Проверка состояния +python check_services.py + +# Просмотр логов Docker +docker-compose logs +``` \ No newline at end of file diff --git a/python_parser/README.md b/python_parser/README.md new file mode 100644 index 0000000..035aa05 --- /dev/null +++ b/python_parser/README.md @@ -0,0 +1,197 @@ +# NIN Excel Parsers API + +API для парсинга Excel отчетов нефтеперерабатывающих заводов (НПЗ) с использованием FastAPI и MinIO для хранения данных. + +## 🚀 Быстрый запуск + +### **Вариант 1: Только MinIO в Docker + FastAPI локально** +```bash +# Запуск MinIO в Docker +docker-compose up -d minio + +# Запуск FastAPI локально +python run_dev.py + +# В отдельном терминале запуск Streamlit +python run_streamlit.py +``` + +### **Вариант 2: MinIO + FastAPI в Docker + Streamlit локально** +```bash +# Запуск MinIO и FastAPI в Docker +docker-compose up -d + +# В отдельном терминале запуск Streamlit +python run_streamlit.py +``` + +### **Вариант 3: Только MinIO в Docker** +```bash +# Запуск только MinIO +docker-compose up -d minio +``` + +## 📋 Описание сервисов + +- **MinIO** (порт 9000-9001): S3-совместимое хранилище для данных +- **FastAPI** (порт 8000): API сервер для парсинга Excel файлов +- **Streamlit** (порт 8501): Веб-интерфейс для демонстрации API + +## 🔧 Диагностика + +Для проверки состояния всех сервисов: +```bash +python check_services.py +``` + +## 🛑 Остановка + +### Остановка Docker сервисов: +```bash +# Все сервисы +docker-compose down + +# Только MinIO +docker-compose stop minio +``` + +### Остановка Streamlit: +```bash +# Нажмите Ctrl+C в терминале с Streamlit +``` + +## 📁 Структура проекта + +``` +python_parser/ +├── app/ # FastAPI приложение +│ ├── main.py # Основной файл приложения +│ └── schemas/ # Pydantic схемы +├── core/ # Бизнес-логика +│ ├── models.py # Модели данных +│ ├── ports.py # Интерфейсы (порты) +│ └── services.py # Сервисы +├── adapters/ # Адаптеры для внешних систем +│ ├── storage.py # MinIO адаптер +│ └── parsers/ # Парсеры Excel файлов +├── data/ # Тестовые данные +├── docker-compose.yml # Docker Compose конфигурация +├── Dockerfile # Docker образ для FastAPI +├── run_dev.py # Запуск FastAPI локально +├── run_streamlit.py # Запуск Streamlit +└── check_services.py # Диагностика сервисов +``` + +## 🔍 Доступные эндпоинты + +- **GET /** - Информация об API +- **GET /docs** - Swagger документация +- **POST /svodka_pm/upload-zip** - Загрузка сводок ПМ +- **POST /svodka_ca/upload-zip** - Загрузка сводок ЦА +- **POST /monitoring_fuel/upload-zip** - Загрузка мониторинга топлива +- **GET /svodka_pm/data** - Получение данных сводок ПМ +- **GET /svodka_ca/data** - Получение данных сводок ЦА +- **GET /monitoring_fuel/data** - Получение данных мониторинга топлива + +## 📊 Поддерживаемые типы отчетов + +1. **svodka_pm** - Сводки по переработке нефти (ПМ) +2. **svodka_ca** - Сводки по переработке нефти (ЦА) +3. **monitoring_fuel** - Мониторинг топлива + +## 🐳 Docker команды + +### Сборка и запуск: +```bash +# Все сервисы +docker-compose up -d --build + +# Только MinIO +docker-compose up -d minio + +# Только FastAPI (требует MinIO) +docker-compose up -d fastapi +``` + +### Просмотр логов: +```bash +# Все сервисы +docker-compose logs + +# Конкретный сервис +docker-compose logs fastapi +docker-compose logs minio +``` + +### Остановка: +```bash +docker-compose down +``` + +## 🔧 Устранение неполадок + +### Проблема: "Streamlit не может подключиться к FastAPI" + +**Симптомы:** +- Streamlit открывается, но показывает "API недоступен по адресу http://localhost:8000" +- FastAPI не отвечает на порту 8000 + +**Решения:** + +1. **Проверьте порты:** + ```bash + # Windows + netstat -an | findstr :8000 + + # Linux/Mac + netstat -an | grep :8000 + ``` + +2. **Перезапустите FastAPI:** + ```bash + # Остановите текущий процесс (Ctrl+C) + python run_dev.py + ``` + +3. **Проверьте логи Docker:** + ```bash + docker-compose logs fastapi + ``` + +### Проблема: "MinIO недоступен" + +**Решения:** +1. Запустите Docker Desktop +2. Проверьте статус контейнера: `docker ps` +3. Перезапустите MinIO: `docker-compose restart minio` + +### Проблема: "Порт уже занят" + +**Решения:** +1. Найдите процесс: `netstat -ano | findstr :8000` +2. Остановите процесс: `taskkill /PID <номер_процесса>` +3. Или используйте другой порт в конфигурации + +## 🚀 Разработка + +### Добавление нового парсера: + +1. Создайте файл в `adapters/parsers/` +2. Реализуйте интерфейс `ParserPort` +3. Добавьте в `core/services.py` +4. Создайте схемы в `app/schemas/` +5. Добавьте эндпоинты в `app/main.py` + +### Тестирование: + +```bash +# Запуск тестов +pytest + +# Запуск с покрытием +pytest --cov=. +``` + +## 📝 Лицензия + +Проект разработан для внутреннего использования НИН. \ No newline at end of file diff --git a/python_parser/README_STREAMLIT.md b/python_parser/README_STREAMLIT.md new file mode 100644 index 0000000..d3b0d36 --- /dev/null +++ b/python_parser/README_STREAMLIT.md @@ -0,0 +1,186 @@ +# 🚀 Streamlit Demo для NIN Excel Parsers API + +## Описание + +Streamlit приложение для демонстрации работы всех API эндпоинтов NIN Excel Parsers. Предоставляет удобный веб-интерфейс для тестирования функциональности парсеров. + +## Возможности + +- 📤 **Загрузка файлов**: Загрузка ZIP архивов и Excel файлов +- 📊 **Сводки ПМ**: Работа с плановыми и фактическими данными +- 🏭 **Сводки СА**: Парсинг сводок центрального аппарата +- ⛽ **Мониторинг топлива**: Анализ данных по топливу +- 📱 **Адаптивный интерфейс**: Удобное использование на всех устройствах + +## Установка и запуск + +### 1. Установка зависимостей + +```bash +pip install -r requirements.txt +``` + +### 2. Запуск FastAPI сервера + +В одном терминале: +```bash +python run_dev.py +``` + +### 3. Запуск Streamlit приложения + +В другом терминале: +```bash +python run_streamlit.py +``` + +Или напрямую: +```bash +streamlit run streamlit_app.py +``` + +### 4. Открытие в браузере + +Приложение автоматически откроется по адресу: http://localhost:8501 + +## Конфигурация + +### Переменные окружения + +```bash +# URL API сервера +export API_BASE_URL="http://localhost:8000" + +# Порт Streamlit +export STREAMLIT_PORT="8501" + +# Хост Streamlit +export STREAMLIT_HOST="localhost" +``` + +### Настройки Streamlit + +Файл `.streamlit/config.toml` содержит настройки: +- Порт: 8501 +- Хост: localhost +- Тема: Кастомная цветовая схема +- Безопасность: Отключены CORS и XSRF для локальной разработки + +## Структура приложения + +### Вкладки + +1. **📤 Загрузка файлов** + - Загрузка сводок ПМ (ZIP) + - Загрузка мониторинга топлива (ZIP) + - Загрузка сводки СА (Excel) + +2. **📊 Сводки ПМ** + - Данные по одному ОГ + - Данные по всем ОГ + - Выбор кодов строк и столбцов + +3. **🏭 Сводки СА** + - Выбор режимов (план/факт/норматив) + - Выбор таблиц для анализа + +4. **⛽ Мониторинг топлива** + - Агрегация по колонкам + - Данные за конкретный месяц + +### Боковая панель + +- Информация о сервере (PID, CPU, память) +- Список доступных парсеров +- Статус подключения к API + +## Использование + +### 1. Загрузка файлов + +1. Выберите соответствующий тип файла +2. Нажмите "Загрузить" +3. Дождитесь подтверждения загрузки + +### 2. Получение данных + +1. Выберите нужные параметры (ОГ, коды, столбцы) +2. Нажмите "Получить данные" +3. Результат отобразится в JSON формате + +### 3. Мониторинг + +- Проверяйте статус API в верхней части +- Следите за логами операций +- Используйте индикаторы загрузки + +## Устранение неполадок + +### API недоступен + +```bash +# Проверьте, запущен ли FastAPI сервер +curl http://localhost:8000/ + +# Проверьте порт +netstat -an | grep 8000 +``` + +### Streamlit не запускается + +```bash +# Проверьте версию Python +python --version + +# Переустановите Streamlit +pip uninstall streamlit +pip install streamlit + +# Проверьте порт 8501 +netstat -an | grep 8501 +``` + +### Ошибки загрузки файлов + +- Убедитесь, что файл соответствует формату +- Проверьте размер файла (не более 100MB) +- Убедитесь, что MinIO запущен + +## Разработка + +### Добавление новых функций + +1. Создайте новую вкладку в `streamlit_app.py` +2. Добавьте соответствующие API вызовы +3. Обновите боковую панель при необходимости + +### Кастомизация темы + +Отредактируйте `.streamlit/config.toml`: +```toml +[theme] +primaryColor = "#FF4B4B" +backgroundColor = "#FFFFFF" +# ... другие цвета +``` + +### Добавление новых парсеров + +1. Создайте парсер в `adapters/parsers/` +2. Добавьте в `main.py` +3. Обновите Streamlit интерфейс + +## Безопасность + +⚠️ **Внимание**: Приложение настроено для локальной разработки +- CORS отключен +- XSRF защита отключена +- Не используйте в продакшене без дополнительной настройки + +## Поддержка + +При возникновении проблем: +1. Проверьте логи в терминале +2. Убедитесь, что все сервисы запущены +3. Проверьте конфигурацию +4. Обратитесь к документации API: http://localhost:8000/docs \ No newline at end of file diff --git a/python_parser/adapters/__pycache__/__init__.cpython-313.pyc b/python_parser/adapters/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af840e817ca7d488457e8b605b9d08c50de413c4 GIT binary patch literal 172 zcmey&%ge<80@v1LfT+hH0tOhNjL$4U##DxM22Do4l?+8pK;CDN)GcpktC-N@)S}`T z-^A=<-KrRu)Z*-t{DPQ*%94!yy!e8|BA{%1avG{YOkzr6K?z7(e0*kJW=VX!UP0w8 f4x8Nkl+v73yCPPg*&w@%L5z>gjEsy$%s>_ZAR;Zp literal 0 HcmV?d00001 diff --git a/python_parser/adapters/__pycache__/pconfig.cpython-313.pyc b/python_parser/adapters/__pycache__/pconfig.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34fa65daaf59b3d45658af0d60abbe9c1e495e8d GIT binary patch literal 8206 zcmbU`ZB!Ijman?Hx*Pg~k8VIfutX4Ap+P}ZBqo3wBie8%nstPPw9sH$^NLC-VIn`bKIHy*!*iHyC=^6*uA%! zY8oV&oV|y7ecyZc-FM%8@7{OsW6o+#B>?|9aOKb+a|rn(Ry458BXcH-kk<%DII5Wl z_^WHC_UHs18*ifpTJ6&djQVR3j8%lAIej<9F`NNPBWHp#g-eCf%vqqcayBT_xO6Bp zxJ)SRoCC@%E*r`mZUvONTppD9+)5}5xI!pbaV(UpxgsdnaK+t}VB$)+wOlDz#yPol z+|ig4&U#jj}+S7(h(_5 zZv9X`0X^5`GxAC4rgVMj{HgBXk><$ILFB#)$6fewdZR|1kHnYcGtw=2M4DP=VNFBB z$g}|I-U6mm(kC$aGAb~&N4z01L3;@m3Ey#C)>3ix9MY*uAD7Qcw-PhYEBzuWz0KX) z94Uz_;kNW!*c@26x;+a#?@Bl08~LWfxI5gfE%5;t)Tv*9A+YB#?BnGGW}5e+6l-yY zi}DE=0yD_J1c`4-p8z(ZepAvl=`OT=C`~C$YeaCj#&`58Y}lL9C58D}gS&+rPQewq zI-cPg=h0^lwCo#BRa^INtf{CSw#4!3O%>HuRY|p4sKrOO9BAD=Y*NWQtr{Os>rQT- z&(4O9_S$*8y`{Zj?{Jz*tm3X+4NdJ%bHstmd0Dy*D!+zHP)|FY>&Oc17z16SDd6gE zqu%9T0qNO@5j%fVv9YGIHeyq8>D>wtb;E{AkalSkh#Y74ru4dWS$c<+kGtd(F8O$+ z`~oQQxOV0*f{xBDRNj{^MKX~2`_gYfcW<*`aW6}6Rn$h%-$`TYS@}S^8+j6|U=JYV z9rXy^maem~CwE!-mvB@*1j5^3hd1Ys)g4wnK_7tOo&XGXO1jgd10EWnz0vT^ZGqx7 z;vsF|JeLATbs~)l9%|D(#in^a#l)#|E4pWPICY9q@Pz{29-l&sVFBtXeg1&2JLC-? zQVhKBXt%#t#8E7(>}jg&@`ye`?Aqr&ELIG6?eK|*!@*EjXefLr$io-`db@l27B_Tx zd%dAB4h!`J`96QYD>S5J&d&<$yZtycd`MUc)2xF}L{l0eGiJxMd8KS#Io5u;di==S z+oI-5Nnbe!ounsu$qY283fTzAYorqiRA@_9+k6{%XNuE#$fkMqfGTMB@QUYpyN1K{X`CePuBa6`2r%&&kE>o6kES9+#U8F1g-Jj zL7z|rjV}1aY$!&^tl4_D_H?b3Suqir>W!MWN&0O9I-o^sNNnms;0$X>tj|L_6RXg+ zuM9>bc(Vv@KdyfXX!njr*$Zc~6U{;et+$wTqKj9dO}(YHTKrejRhxBjJJvKFnjU$| zL$#$nPKUR&Cbvq1HnRjYUUt%<6LpnD)Y-}IOhST1Keo13-9B&+X2KGl=5-6J+8_jZSahkZO$T=juqk2fH0cO^*C^hI=z-@*x#Y_7MMG5y~= z&W2Bg-(nt#xT(iebE(mkT*{fEr20iaFNVE*k553qsW4#a{tz5!Us%BVRbbWDK=7zf z5HK(Ricr8GcIp*<*mo?f7<&RfFYoIWoNA}K22l?<3lLvM_VTg|H9&=SDgFWqw1%wF z-Zz@2&8%!@C-hfSCsVIlCM~mRnP(y=Ewi@tvwf%gMh}eJ$9vx$xHRx~AZn`~d3wf{ zbvAe^IMzG9BWiO(eQm|NgO>&`2cwqSx1jm#fl~)w>bevh*(q6SXU#U*=DNg0ZLX-< zCFxy{9@50RSws{2^vT@Da=o9xet{_)2ffEcQ1GG+$7QMBqzI5dXNko`z#A7fSM>tm z%nlBzUO-WAzV2ssaFgIN&@Uvrj7)SH!Gi<7p0GAR*am#?6VZr9$T#NPvEs|7sM#s$ zosavA|DTk?X5g(DTAoJ1gsnIm8b`7t3-%`@+74Y$Ax*MGhN!tz(wD|10yQQe1u#`_ zYoQg5L^BTbQa{a~^@1?{q%+~qz)Pce0KCql)A+@yIIwz-;`QKl5`HaCi{*kx+5H(I zXxE{RB)&|7uhC;n@CB-UaP{mjt$_1BgB8GzsN^sQyazAqwLU`vygY4)}P59`s}3 zJ*MabelhG!6<`;LlG^L<3HyV*R~S;vKaco?p>EYxDX9m2Vz_(I8}2zYkBdD)xYASl zB7s2MUJYQ55R52hA0JMPv-o)oT)<3$D>y|QB;rMhelHHH_fzdkEp|eu_`gt$kgv^Y zuMUqFU!kXS%H^E$nKb)1nPn4>Xr^nV`D=4F)bD3xjqI7p$Q;>ozo2xwph7OF__Cl< zHszj7nawVr_*pc2^GWm9X?gc7j{7-9a!%Dr%hzf7P>UIeB`0bwnX%`d-ltV&9XVs> zsH6DQ&Tp*gqbsAHlUf zn8__Xxo0MK)#*JCHj~1tSRJusOZu$1e?WhrK_bGr04>iMo-;zePvwz8qsQPe*627L zS&nkBM{)XYFY`hLI$d?7n2XjOfZoI z%0(9>ZYrpi%!?piqd^1ZEc}9i z@fyelZy2EDxW-OnHYguw-ClPEW>cVVP$cSGy5nl!h4EIXSJC@L-V0Yf4d$JE*O~ny z*gfAJ@E`Umt1^dk2py~Ml8ZHC%;>&C| zfk7pXJcP~Q#xXh-A#CO;NCIFV;*gwdw4v-v;4ztsRhgDa9Uzpa6QMj_F0?8It(i4Q z0rH^~yq>2$`Xy4}8V*_yDb&!9tpTL#gv%`s3#ar4CBn3B z2_(&l0rnC|>djly1=VFF0;=|uWG9$718`At5O#FpQB>h4$XlqXr;@adQDBBMQyF~slMvp`n0s4 zehi~|&_klt*oVObruiyB@BqGtC7sLg7j>(^3bl|So&v6n2dr%{SV>7-%8CiXRzV0J z6%|ALdR7cayn%>MRCIhuF=Bw(?-L-p<-@f#>QD7Xg@&49>I($DVL#um7*!0q;|LHi zYKvmzd%c3-9a2)-{g7dXy@R1R+UpC1y#lAo;unK`_^uFE7`W~ZijemDMR*bDR}Aik z_MwnZ(PP{!Gy=7-3k&s;AZ6#V9$yFpUkI<;krUOe(6ADPIwIg@uh55mLkgp=2JTsi z&J{B}@E!39YHlldfM!v!JTejwmcuys2kzV?1|vAW22S($m*xu zE}N;Yy;Xm${>JuywKrbhKAAm{ajtos{?bu=ZTs)-jgqDDI|z}p)iGPoZ=E)m$mWv! zt_@cQ-W!N!ZGCS5=ns#t{xv^2aB`QFwe`L|_vAhpVp}mrzj5&5!1;kIMOVuv%WgE@ z+I?-eRPe;Kb-QfcK5Ne&6<^tMvSrqqqY@rIfB4GAt96rgH-uZm*M_Bn#%XJlY;C%i zzjj=l&R;L*uOF?EEZc5mO^F}m0TLhBcJaXZ1Jl+r*;;n5yfSL9dar5x=db|k*Y3$C z*t@%LUoCyFbZX7j^2zei>ert*_rxntN|vW? z?|?#^VgLF4@swh^phhmJnYM0{t(zcD(HOT+TZ?3C5o8Z**1qe!P>6j%P))N`IeTdatPBA=1T&-fH{K64%%~uX`IeMeViM z*Gv?{TJ&E!O0KPu?X~bE^8hrPJ7%A@7Rc5DkRfKGt?X<`JtCAazJ++2Uw`T6C*Z-3}vzgL=#@d?=hR-%zq5S97navjc z=S)d+2Kjt_DwJPjWHmeKFUlw=A$&CW`Cdo{6^oA-BLY0hi9LRQ1QR@X&4)1ggc{*P z^bCRNix^uk&I2%##d!Y3q)Y(+zZ1^{>R30vu3^BbFuf43i^3pqR#H3AIqU?FAvjH7 zm=Kr>N1#JEioKTkcerkBSJIPf-SDQTP+)sVtePIiZ>$PWJr#eWvn0p4!e2vw2tM&y zC?1WFhv^0;>%Y@o3>$l%Vjv~LGf)%FDT8;p{8bn0F4T<&q}DDu|5?ejVkRwLGUb0i zYj%M4fp*rmLdt($@*b3)?~!tQqc)#p^8F9&1@!$%eW`q@u!6jw+K@`$vNbUDrwjwA zQztwHlkak7sPB-NkMlj@U@#yGm}LkUb}NjU&InzI8$$3f>J{!f*xQQ@nqlQ=t;;C`mjJSm`)|0-N z6>%G3?4vtlX^5v2#x?PaSO(&mgjqX26tg4lAWYHtmRJ_z*@P(`KM>17drL#0n5EjN_{iX9-g=(H~olcoE8DjI9BD#1LCY3d&~K^{|68*~Rz= zczWJUdj3pq$xLS9%+vcH*i>p fTM1j@Q>7CuxYGq_d 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 Y8SgR}-eph)qE9R=+)Rz^MchCc08Z#^5&!@I literal 0 HcmV?d00001 diff --git a/python_parser/adapters/parsers/__pycache__/monitoring_fuel.cpython-313.pyc b/python_parser/adapters/parsers/__pycache__/monitoring_fuel.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1954ec48592f00fc3cee4023214e0c06c3d2a324 GIT binary patch literal 9730 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 literal 0 HcmV?d00001 diff --git a/python_parser/adapters/parsers/__pycache__/svodka_pm.cpython-313.pyc b/python_parser/adapters/parsers/__pycache__/svodka_pm.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09b5d5b7961123f134ab6f9bd4c44feb97b609c8 GIT binary patch literal 12754 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 literal 0 HcmV?d00001 diff --git a/python_parser/adapters/storage.py b/python_parser/adapters/storage.py index 439214f..45cc8b8 100644 --- a/python_parser/adapters/storage.py +++ b/python_parser/adapters/storage.py @@ -15,24 +15,53 @@ class MinIOStorageAdapter(StoragePort): """Адаптер для MinIO хранилища""" def __init__(self): - self.client = Minio( - os.getenv("MINIO_ENDPOINT", "localhost:9000"), - access_key=os.getenv("MINIO_ACCESS_KEY", "minioadmin"), - secret_key=os.getenv("MINIO_SECRET_KEY", "minioadmin"), - secure=os.getenv("MINIO_SECURE", "false").lower() == "true", - cert_check=False - ) - self.bucket_name = os.getenv("MINIO_BUCKET", "svodka-data") - self._ensure_bucket_exists() + self._client = None + self._bucket_name = os.getenv("MINIO_BUCKET", "svodka-data") + self._endpoint = os.getenv("MINIO_ENDPOINT", "localhost:9000") + self._access_key = os.getenv("MINIO_ACCESS_KEY", "minioadmin") + self._secret_key = os.getenv("MINIO_SECRET_KEY", "minioadmin") + self._secure = os.getenv("MINIO_SECURE", "false").lower() == "true" + + @property + def client(self): + """Ленивая инициализация MinIO клиента""" + if self._client is None: + try: + self._client = Minio( + self._endpoint, + access_key=self._access_key, + secret_key=self._secret_key, + secure=self._secure, + cert_check=False + ) + # Проверяем bucket только при первом использовании + self._ensure_bucket_exists() + except Exception as e: + print(f"⚠️ Не удалось подключиться к MinIO: {e}") + print("MinIO будет недоступен, но приложение продолжит работать") + return None + return self._client def _ensure_bucket_exists(self): """Проверка существования bucket и создание при необходимости""" - if not self.client.bucket_exists(self.bucket_name): - self.client.make_bucket(self.bucket_name) - print(f"Bucket '{self.bucket_name}' создан") + if self.client is None: + return False + + try: + if not self.client.bucket_exists(self._bucket_name): + self.client.make_bucket(self._bucket_name) + print(f"✅ Bucket '{self._bucket_name}' создан") + return True + except Exception as e: + print(f"❌ Ошибка при работе с bucket: {e}") + return False def save_dataframe(self, df: pd.DataFrame, object_id: str) -> bool: """Сохранение DataFrame в MinIO""" + if self.client is None: + print("⚠️ MinIO недоступен, данные не сохранены") + return False + try: # Сериализуем DataFrame data = pickle.dumps(df) @@ -42,24 +71,28 @@ class MinIOStorageAdapter(StoragePort): # Загружаем в MinIO self.client.put_object( - self.bucket_name, + self._bucket_name, object_id, data_stream, length=len(data), content_type='application/octet-stream' ) - print(f"DataFrame успешно сохранен в MinIO: {self.bucket_name}/{object_id}") + print(f"✅ DataFrame успешно сохранен в MinIO: {self._bucket_name}/{object_id}") return True except Exception as e: - print(f"Ошибка при сохранении в MinIO: {e}") + print(f"❌ Ошибка при сохранении в MinIO: {e}") return False def load_dataframe(self, object_id: str) -> Optional[pd.DataFrame]: """Загрузка DataFrame из MinIO""" + if self.client is None: + print("⚠️ MinIO недоступен, данные не загружены") + return None + try: # Получаем объект из MinIO - response = self.client.get_object(self.bucket_name, object_id) + response = self.client.get_object(self._bucket_name, object_id) # Читаем данные data = response.read() @@ -69,7 +102,7 @@ class MinIOStorageAdapter(StoragePort): return df except Exception as e: - print(f"Ошибка при загрузке данных из MinIO: {e}") + print(f"❌ Ошибка при загрузке данных из MinIO: {e}") return None finally: if 'response' in locals(): @@ -78,18 +111,25 @@ class MinIOStorageAdapter(StoragePort): def delete_object(self, object_id: str) -> bool: """Удаление объекта из MinIO""" + if self.client is None: + print("⚠️ MinIO недоступен, объект не удален") + return False + try: - self.client.remove_object(self.bucket_name, object_id) - print(f"Объект успешно удален из MinIO: {self.bucket_name}/{object_id}") + self.client.remove_object(self._bucket_name, object_id) + print(f"✅ Объект успешно удален из MinIO: {self._bucket_name}/{object_id}") return True except Exception as e: - print(f"Ошибка при удалении объекта из MinIO: {e}") + print(f"❌ Ошибка при удалении объекта из MinIO: {e}") return False def object_exists(self, object_id: str) -> bool: """Проверка существования объекта в MinIO""" + if self.client is None: + return False + try: - self.client.stat_object(self.bucket_name, object_id) + self.client.stat_object(self._bucket_name, object_id) return True except Exception: return False diff --git a/python_parser/app/__pycache__/__init__.cpython-313.pyc b/python_parser/app/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c812a10f3a6b11f3367922e3766aa0ca698de86e GIT binary patch literal 167 zcmey&%ge<81TxpwWPs?$AOZ#$p^VQgK*m&tbOudEzm*I{OhDdekklvnW?p7Ve7s&k#{RDr_J5DU3o08E1%_e6|e#xXX!5NDq=-l#jKb=XLOfzm9o;VGFHZ)GrP;X zmarvV6|ADGl2vw9v8t|WR^8=bj;^I_X_u2Z9fGIKyTQ29|&(>`4Y3g$^I zpwt#4tMyo%f?OyU$;F;pxung=>O6IBSuZ1bmrLcG7Evy1GsxxT$r{(slY0rzT_IO` zjGhLM$*he%<}RX+#BcNzJhbF^(>L=+KjSm z#v4s|XgQvn%DL2YZ=*vpEneK86eywdLPX_vCrMyaB-DX%L%49Hp#C7wQxL)4SCdqA{YH-^~+!DN6=i&9Wd3kM$^Qr=`&9iu|oQKzz z^fLxMaR={-I~VAQ_IOWp@SfP3(i5xZDRJApC3ePZ??COh&#L|Ed3fzeKci9mowqoS zyHaYuW}Xte<}I;1UVA5Mzk62g*UrOh&%C^P;=GoESMMxd>pbh_y&L~R5PSuK;4!$z z^f{fpL$cJ#`((E)w@D7+uy|N>?f;CDdt3(9xNT@4q#Ab*1w$^AYT51!hT8Y;QjOb( zhW)Dbz}WDpZ;;bDJNNJ3+xgIde=IaK8c@x_kS`PtxDUrT!3p7N zR_ROClUXjs=weR9gh~G^-&bCXJfU1vF47bY_(uF{_TW%(Y}j|)OHbiUWct-hk2&0a z-{5hyWI3MItU-TpfDQ2p8m6`>uPU!Amz6h^x0MNpa!z^4CGniB7Kv;Hf-u!Yc?p@` zQ!YhLDVHNBluMw0?4SqbedQfIzOGD+7xnDwanST1c4$*G=)gJ&_v3Zk9Vp|S$TJSS zFcCQsIjQkLp&+#yTvpz8D3=^yKcT#aVopV#L?XR6f#TkaJgK}($=_Dq#w!<5>_z1* zhw?HQz5EB$%I4PQR+mvVg@!`IeqMXkg2^4Em6$y`<`4MBhP)x);h-wEUha8$ zCIT8TMqQ{H+30A9wSwG*UoaQJXBgdUCG`^zMzZcujCcG#Xhh^GbA~vc(V|VBV3=OO zD7}x)KZ*WEAH9LjIf?Fh1d-^L$YaS)y@=ksth^o`p_iTm`KIzZbtq=agmN)*ih6qn zr%T{<5j;+T`J?DaOoI3bgNXyLqN9oZ;w66ebCjrB2C$C(fzWs^rugvCfR6-W%l$!& zfyMujZ)6M-(-LnOCR!!lVHFfCLEtj6Ce9=n9vShmteDq`Qll; zlh_*Yfe14WLzl38JgCN_{^L*)JS9l-$e~S^A`%O}W4@tb-+jaWxFiX(uOSDuFi6vi zX3q_$U@!R2`WH4mx9RyUlQ!px9ntKfGY=|R)rzq?KA)B?7ss<(NVxb}(-5S6nAWv& z76bn%U(WAh*uRA-fYo`K8b!0{bsk>CDAAxWvar}X1OxabE(<8$>;DcS-s_1(cS5Kp zqJ(5$_a!119+N(^p3$A5Q^|W;e%w7u<{=7ZsHl(bjFQvmH0U{-U~S7%Qx-yFvoSs! zOg(D0yw$t6eMhHP-gS4UnnO=J?~-|xd{`^EwH?C9I>tr^AQrqsgK8$GJyr%M2gbtQ zfl*9kHFLy2GRls7NA7c(Rl{gdHDlbzkljLeBJ3mK;m}Z=5wxnBsl6Qzgj7rLcn~Y@ zkS1=Dk|s+VYcGv8BVj{>7VJg9r;Jr7DSKh)xuNHeUM(tl;qK?|e%^DnsAj6D`IDmN z$)eVHte!X7&?RH`q>QxE@R3XVe3)F<}fWB)PF{G z(AKzyO!UA6*J^dm=qnfG0I6Ly0}tLqFfRv4BIp;Up|;qzNr}alNY_1}fLJ9Q5YjC@ zH@S`}m;RQU7IMm!Tri~J=o<9FQX;d0Uww(i27pQEaM)iuaS+>CA%xII`u<=tby_Iri8&o-JQIwiPNciKs1lf87{d-LO zuGC}776OL85#Iipl1}88 zoP*rxm(&Zfj?_2^C|jFUlYVqaE~H$^(MewhAtP;u#rrZt=y`6b&{w0gw+KE6eTU!| z`bfp_3vt^7Az(^7a~7r$x&Y)7if@PsRHd{ zeZAF+4Cle(H7*b#&m0hb6J)w^zLzxdmJpa5@k*0J`CBBS5*r=;ak+cQHxPnXgKJbLNoG-15WQKOv#$fWz@5 zB;-@nh8aSQgtD5qtLI?*?p@ow+js5m^zOfFZ>K6YfA-(FR7*H;G%)&L;DSNT^*=P` z9|-vey--XezEDuLGyi~p=vX4=g2Y--0oCd!j}uyQ5EkR0KLkT42nJc2PtD`mDrD^8 zrsD-k&0?Al6*@i!Pl$vkGI3*6&E!wy6zxYwOE5e@N?9u>bM(IZQ6o~z)=szEdtmSG z-u7)53_O(qG!TA6#lV)nCH1h;p%(4x+285zY2WRIyM3_J?FIW@_k|+v-KiN=C+@YG zhDRTSv!CG)3@0!+DZ%6w!ue)>KflhfpBk84@;OPy8R4Z3w z-ofz582k%(dW__*nxiS;xL?U2w*^LSjn=CBC`%RRy%xOF){~L3rDi743<(zN1v4WU zRfSDXkV3*=y_X^_ERH|G^A5shQAIyD4;=i`tlGkOy%Ls!7c-6l#1k?TZH%+PGIM(rh2c1OhSn6j^k*jG&2>!$20BleXOE2ivi5qsO!g6gXk&Z&y^ zk&5+KOBfANx_Yu< z$IlI)G;}K?$F7^C%Hr!5OIiMJZ9+liv-Qt6UN5i~+G2t=#}+FVs#cu4=f!)z=bb8P zJe~dP{OV}wvS``zXmQn4ac!iy_PWJbU_EV#WefR^sl290Ueo!*lX>e-o1S z%hiIV(b9@&Y1KK~i?(RFW2(G9QeKa@s03qqWW2Jny$lZ@S}Ebfto5KjG7$ZdBob{Z++HbtRMxh= zRQfny1pRS=38^2KnuxBHK#!NsFc`_(33ANHJ9;=wenuL13r1la3D8_#h+551gaC>> z!o@9cj)c3SX2)lwcMyQsEK`amH}_k5Fym6aMcrH=Q;Hi?Fb7hvL>>b?MT2Z0v#l>- zV965VjBN&P5~MM$QcMD>P0E!p39y`H6O?qq*h*%U&4f(!<>)c81^M(1AUzUym_-J^ z2sNEB(`Kk?LLvBtxFuXoC;4T{*1m)}m7;(-PdST}Yl>3M4lA$$79GAz%A08{|3!6c z>VR9V%a$#3D6f*`4)+2I5mr0^k2oZP3G*)D9*Bagu@Ty^e`v6OBdO%G^I;zjfL&+m z>q+-o=^VbDTqi&W#SI+_U#? zXQLLw#{!Xk>o+ty*0oJ2hs&G1URT>&4^*$cwl}6Jr}Ip6ksD1L+en@ zAWrnArm;^_0tp9AZ9hO1LjW~APIL&t3?YYI3KpjLV-!4yV2=JR;c`~T&yy0DJ%QXe z=#6&}a24E`RKXTgMl83)6cn$OESoB6j+8V{mb9MEj#k&6&OUQ6l2LIrzmoJ}$uj7b z8EUXDl2>=WWHN8%Y4bHr4PILU#aVSO>%}bOBt0fU^;v}i$N8<7%5h7h*p}$TvDxx2>UIEd}c+Sl{T_uoAyj_^rlo zOAL)^2+==pI3i;3lg{9)fl?j|Ua zq*$&?ie)pzvMrrhUh$<9%j~bwknud-;2-eC5#sPh#LthvK*Q5EAU0e$*pdK>-zM1Q zRpm^W%;bfkV2;%g(mW9+n_b(U)FYDysLs(*N3h95jSh~UXg8N?oF9v=hjXxy1Cbst zOozp$!CT>|_a)qizJ!~Q&Ka2D1^{oxxgc@h?INy(Af#LiBCcr=THQTLAg&2FBFR|K zlLm1u(sSJe;+jBb^>=_I&qiEJlPNltaIXk)h1;WD9C4-X$dqdyj8sEh(~XZKg#jLu z;{$GK%7`Pbi}qz4adqk?%y8vqqOcm`ddqbK;##Y7PI34&#C4JS-2~$Lci?ZGv*c+( zlM_Y$58wOeTQ0L#D;fL?iUSU$lC|~*{%8;LC**1A9u@7^&e$Z1JgMQRS{dnC(&DJJqXWYtM*8*xX5Tp_r4Dce23cGDHb_JSwdM}eCHnS%Wk ze4T>35%g#qsn(#m4P6mYL2KoqTa zHcA1xE-5%68>2W9J?sGr$p3Je+0#Um|G^0RTg>gqoeld9_}Ce|^*AZEV+c|pKjRvc z^_solnTMZvc*?#!VqdPTxO2+h9X!RnBvFy?EF6`ld?iPG{c$5MbKAr3y5AOZd+%( zQqx|Bho5bxgr99$5BkHkM1Q!BUiffB;r3kVqwKcrS<=TQ5%kAq6H-6UG7+6CfgUfI zq4Ra`cD~~jv)w8Jh!$S&>HVw@%&0{)@`8Zg3>c3?d!HMOC(Q%n8B<_9g8S0Jc;?%L z@ho!2yf7Z;DQBjE@vPzd;agd63ddV`n6zCn0_Px#39*SE=Ax5c7rBhau06TV*rdmv z8s7%H1W*Zax9)ZkI+G3wn~Ao~D3`!4V05%0*5Bypr!BO89e(N$@I9)bWBrTZVIexA zldjOY@Y~D=5(J1XJO@-2o#uLKp;9!I^L9Wm-XR>>qDB(3MU8ao9*UWr1Mv2SJ3}-E$B%t;3XwIsf2H&@uP47Pb%RZ-GnFg)!7v&yg#F}E7_22pZ}8n z)16@HpCPVjlg9gvJ$oMJxC^P`J$w40nIT=Uxl8)P!EbP{$T9$MgFQ1?4{u<%?+Mx% zaZ@?#+T30kK~YOVC#LyaaxFP0*1+%UexO4tAuPyI>P!MH{>(}mbQsc zMjnqm%g@?#OOvZeI+D=Mi2aK}opK?9=;m z-OU8R%s;cZITPsfm(&1j0WG=r8mHCU1ITRrpc?9A$Zc-bhKlPG}5d1 zqGPU!hu!1_&RX5RnBsMVkaD)Ja_Z-O@PP={#pfcGmZp2K%^wyW^%it)%OKJzuw5nNXr+e&Y2r#CENd_6kK@Z~WMLF2R% zBb<{NdD0<#wTv$ynTew4s~tw0LmIHp&l=~&b2KNuuj6|MYHs|S*I;w}BUnbh{EX=M z=X{J#7cx3L$Oybtv*-h-W_~<5sBJOOl2CJabo@itApg8p`w%V*Uko+}2afnhd_hKz zu(lCF?k+2)fLvKddwGl;RYu=YsOIn(j!XHOgJNj^OZ&<-hd%D~j^NZd9i~zxuvR4u z0{{4uZ(;Bc>G-En)Q>pYOlOe!DJZ_@&i5x6!AFdYd9E?|7}2QEsco-Ul~_2C`r%c^ zCNwxa?BBwEgx9cKg(U z&01__X`bOk&h<5d#TK$wbzz3D|h_WbwS8)H$;hkAd<(>fkoLdi(s(g{I$V`0dUm3vQ=3-7^(JOmo|vj zXnw^Fx=-7Y9J7InxzQEzQfkikOf}vSX}m*exHFpH6+;RbiH6-`%(zAjiqU-6v_!)K;ZwFj9g>-hoD13vbXp-bhffZOJ04U-{-#?Z!y$MrFm)bTFV zv7Xm)>9j-y)lrX(dCZAA)+#Mqr&@MKT6QYUyD(P@wi<44Jl4m@1NV4ULB&GJ?p&#~ z?U`zGN7~%V205C4JWUJRo&k$A_t+LhBT$Qt<6|}zM~9f zI7JBtoH*e04R=yE@xZfZH*F<8_(=ePJT6F^V&2Jk;6rbJouGe4j}bfi9;GuH9*?GVHPfC1OkauZb1&>%6n@&iX*~E{_UF&zj+_O z-!!_rvjoPkKYhD6p%C&XPTE6l8I6lzJR~MDr3++6qSA~^4WNKmS)O1 zqe~3W2EG>s)bq>JHMat@Xz{XptLCz33sWDjode|G@E3fOKaH0Q$!8`0GQP{#3h_$( zX}k=3Kfv#Mm=^dtf6Bj$Ka2144Zc|@3b{CWC;!1~#p|cX&ffUs^!4J{BQNkp+P&>m!-^}?p%XTu_koe_MNJ0+ahb*)nL9>LA%SgZ`GViYv-_SFL;zi z70-A50JifVvB0-kY0<4ZwtG9Gj_9{-7CDhuvLP?(eOQZJX4^Cm7d7BV#MP;D)>YOFn+o{_&YYOl8Z z-n};)L{+ta4ykH(2dr$<3p(gv!mbuB!A>U=I<+t%o0^$!>jCe#bW`6|MFv!n-Bm@# z%+YMQ%jn*(iYt(1rL77q$arlEkblkBKmjYj^z{ON&e!-ep#K_J8z2V09zWnu_y*`> z4K%SCKZrk11Orm}kv{?byx{9XjnKEy{eV`Xk{@qL;Mh>fq0G>Pp%y1jx&5U^8h5&-Bn^m0PC zYxVr#>g&8`wBCCJI5(^@f@jlK85xJ@i#X=liS#s2yI-X@klO{|Qq9fQ3% zc&2UC%pEjqx+6%@ z6?M>J{9DFPdoBMsS zkMR6Mu2NcZO{}T#y zA&+4a@_zgi2(JP2vY@IEIGlMQs-8sEU%>G`Y`u}BbrrH%ug15qDyZSPl%Xt0Ti(IU zhfoAo_&^R+p%Fy1;d3UUFHrMWxe8Se<-ID1uf{jg4b6?TQrI_yI1hmVj}6(E58_)$ zqBIIZ=6$&e^B%DM_?jwoS=Z;ww0nN!)?^_Vj=jSGqqio#FP3R#t=znERO5z~=VrT5 zE2^m%J33$Yy_VbF!TYar?4r{RI?O$Olo0pYG$A{A;M*`smB`O(1}}ig(V34SlmLDs zi?yuEQ|dWgMyV=N+Vz`J2kjE2-$YJlf8_wBEtiY1<9f{VVfodsh3`?(SYlm=vWp>i zRE1IzI-%R3P8f3cd=xT4DL)8-_FxkAdHrMiE5W$1&pH>xkxTYTCN6}2U^oaCZ*9%YZq2;=xL{6} zcQd(};%0t|Pk{?Rgn(Hs*2?@fe0d$Af-r%ApGtCED&u;gg4!L=^RYDelAxl|LsVv~ z<2zw0JBeFSI}HVWARIfM0P2c!05{0?#GzhY9=Q}xTwYoDIkRb8-mXmdK9V1VaV1(g z{e##vqJ4(P6_GMx`;9ky)-E9*p3on|FQBdiAHmt0b^RYBZx){rfHX1&U91@@A1pT= x51PX950{pfBs7|&%72n}{!?BBKMkh9Q`yaEn)WA|dy*|{#opB41RhC%e*x&E-R%GX literal 0 HcmV?d00001 diff --git a/python_parser/app/schemas/__pycache__/svodka_ca.cpython-313.pyc b/python_parser/app/schemas/__pycache__/svodka_ca.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e04d9685e33ac5b4d273a6f6f8f787c76534978 GIT binary patch literal 1635 zcmaJ>&2QX96d!-C_ak3~B;ACzhAIW4kZ>ReB7~GCjcC%OB@PIXCClA)5|drq9otdE zDJ@bc5{FzWaX>2KR*6Fhq=Z72f58ivWuyuOr`#Ggh$FmbZz`okjO3r+y!p+W_vXDf z&9=52f$`5zUoQVH5b_63j)vS4n(u*dhv-D-X2>*0xoMvAD$e;CVOpeOA`3Ipv`l4{ zoFdN=UF;{iWMm9^R7|Z;)^ZXT7prVbYXiSIQd4 z#LG?);{T!>RZB=b8eB_gsvz7U2BDlzD6ex=(0MBA0+n=;%DO}|OR|<>xp~|7Xo&Xr zF*GLn70YGfqE!l+;(D}dh0f|dGN&m_F-_O1+NQ~JrdjpMQ3d6KX;m^d{)vA~qMEAzAC3zyzzJ*F9iV7X*kVMv{8QD_IIN!!4KCVYfl znHV$P3Tzq}v(`%R(g((*9jt_&Z}@BBvgewNDLA3%IktI>e2|W z%X;QjkxGVaWF%l4imp75|CE&-A$smjuEoj%E7xM>k(Ja!0cxRbl!qw{n%CQDVW~sw zWF2}E&BXY;eLb>+aK8ZS!_fu6__KJcezSfv-i^1__(5EYzkzRCt*^&B@qN(#fYUJ* zGdrYWW>rvrAMdJ1`K4IzG!L+k1*8cqU$%o1b^OrrT$ZtKSXIAbvuxFIO((Rg0h6Er z>>wKZ&-r`tR{U+e4Y&uVe5clLf%p|3SKmPIw&DkByaWE;s(*4%jIwCp3t-+IQU{}R z>8uw2h#SC44O|5awfO6}HiWinV0JHh=Kpzv(X&Xn8`ogR4&1};iDsA_TGuKND3BkI zR%?>xi=aB5?ljROJfu;=G!FAGbI?;6Dq+L2-X~HtJmI;E&eHw>7^0^U9$zz6VXE=; zENao$r1a-BnYQDk1ECWE3zc=fA3({cWo_CwLTb?-T*P)si?$DGa(W)cOT;q+6<~w> zR_JN;tDm2bi`t(&8Cc*CB;i#1BSAWy`&lWb`_BWjOIc)LX3Bq>&i(y5+ha z_Oa(;`(hwW2trB|dnfovi?|yB%Qtuz;3M+OnR5*#-+20+Mpxgby>X}7c&hs#E1i|s zFW!D-Ggr?KG>Ih12koSICLvyhIJ&0!lvb42r*2Pfc7J>+Vg21MOSwY=kVb}Q&1pHN z_-kd$g%^hkph@C^^so7jyF@W0Cfe|pQhXig3kb=Bk+}QBH7l>BZ{O>52zb~p0d9CC ma2)q58GK0k9+I9zS>XCNyEn^+1cbvv50~3?{vz;8-1-+WBG#z@ literal 0 HcmV?d00001 diff --git a/python_parser/app/schemas/__pycache__/svodka_pm.cpython-313.pyc b/python_parser/app/schemas/__pycache__/svodka_pm.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88553be59a01104302c7469f64003e24779a1057 GIT binary patch literal 3122 zcmbVO-ESP#6`$St-0xj~$FX5+O2ekaK?Ot8QX0o`?0WI8lbav~jTk2Di9OAJac4Ke zJZ+#&9YR&3HkBU`X&)`MQlO1U332{~S@AMlsiG23ej{32y!M$iELp= zCdlMdwpCnYp%bQK%~uw!BG|NiwPsh!W|2v++D<#yRiaRhs5C@08YUqcAz>ON5gH>=8YeNDAaR-`37R5F+Cx&b zm-Ns+(o6eEA01fg&kQgrKl7`TTX<;o7XaKpxtq-^&3Bvcx%b_B&Fk*%w0p<>r+XVF z@49!Izk%83?kyN^HXF_BY4>CIk4(zu7G7u4WNtRgl*z&}pPiT_vrIaNWAR*WmWjFi zYb>0rT+Y^4E}&Iy50t5uchI1nt(#Sc-%L23$t`4=oO>;|kY{rCRkX_@Lx>|J5RwQfgdT)mgg%6RgaL#>gdv0j2*U^m0a(9bI5o3o7YwsjqxOY*&2pgD z2>4p?6Ig!gXZktEqK-aqUUH7Sqo1^#OSMW>uddXVD`lfeOk~ZpjMEGL?ZGr=wDsYp?42K z%!=`_RuR z+Ygi-m0p6lS;GFWgP{AMPe+3~!%}Ad4(oPJ!B75twSdZI-G< ziv{h)otLoMN08u3^9rU&1M4;+{U#1S1zvsvWP}2kxOu(#+cYO_1N@(F<>20}JOT>I zhDbB;M-KzAP{}SEcFig|OfG;TIXhEe?k;o>vVO)FeGe-C>+$8F*j@LN=2cwO4vM9F z)4jQa4e0*W{k!`iQwx=1y;OE`J8z=#V>pwmkaE+-5_g*)aDjmW_hFy7moMDgpgfKC zF>5342baIF?BZ%UwN+&4O3!S%B^y zZFeVhmqJuPZCrdV0BReeGKxBT;xYX(K2<4Sw3oJCgp~Z0eQ`K~({TjURXPEX5$TU{ z{1XHoj*5`mQ0ORHoVTxa#{v0Nl(?RQ1 z;Xl!SZ(zh59$CMzKIDyz{bklYc;ta94aL6|mC^8*+5tbuFCm(z%%mQ*3M!(XuNozW zfsmTzas|b$QbtYVd%Pw$Sx2gT_Ck%kI-xI150JB0Pt{JK%X3ZHRTQ0w20J_j;apM2@1K z(VrqbgMiJ^b(nY~UM-ZV?!zQOI3DqIpna6%K~75rXsKqjJz74r!8R?=K|-IFr*M=7 z$OIpzApHgUx|!wo?L0Uzg@f;TPAhg`njM^YAd5&P`H@sgJf2D&zR*c5c^rXD!3iAw z52QJXaR|rZ=TrfJG=n2PF^f*c!9o4}Rty9JUkguv rE&Sl$LjShX6X;ugeofjIV6c67ED&C|w*~myo(mkr$&LVje6{}t-fdvj literal 0 HcmV?d00001 diff --git a/python_parser/app/schemas/__pycache__/upload.cpython-313.pyc b/python_parser/app/schemas/__pycache__/upload.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c91559a6560a7aec3797296f69a194551bc18431 GIT binary patch literal 2611 zcmai0O>7fK6yEi&y=%wL4^BiN1>8aaLldAO1WJVpAwe<3foxK>Vx`r_-XsRcc4zG> zp;R(ZQD`{?sYq6(N~zidNIgIyB|u4g?`2lGI3rac^^_YZL0tRZY={y_+mZb3&YPJx zZ{B?0ThE6=0Rh^dfBZb$;}e9xvGb}ypSSr@c-#;)K@*P)F_DNd5Aj5>?>R2TWFp7B z#2fPwAGb-zm6%G@h)^%QBWUt^LG$WEwTt3n zXFdWiHw0ZEq9zcJCK5^W5LuImSCffP^Acsq7gboWKbOv$NiA>Y3-%mlf+=<(k+5u= z1#%>dFR9EB^IC*t$t@usRheoS8FR!k3>Gkqk!-S%#`mCMd|EKmiz8KrF_$=)7(>53m?-j3eho?cdG7&ZiuN*HE7Pf`Pgyk#2(se)+c;U};Y z?eFXTwnc2c+dOMGozst6_St+kr{~7a9JoDa*6lDCjcqz@tf;e85Az zx=&X$?>3mcX!miu3LH^1Wy!8;er^xw6}lhY!)O3UIZrBpC&5+^bfJ-;79yb`HCo9k z-COIm>|8cuTXR7eZhp}SNPl!L(BJ8#bA>*p)6NCwqH`@mr@5&}Z#$Ri6rH*yvWlc- zCrFC3is16XL0tUHY zg(K*xMDL*wm^8|X3u6PRS@iF*)aE#XdAiIHGP9FSyoC%{+2Z0)+zX1cT2snv?duJp~w z+HAPK6s9|dobWJMv>ADLcGH%LKHB!Vv*~=X>&j?Jy86Y8eEy}ZcmoRpfO{77zB)T5 zU}Pmb{zsucOMrf^EJTU}b{c;)n9vB|7?mbnlEAjFDjkgZ?kxUba6Re?3Ev#=eIeh-!47l^G0RpcA`AOd9s$_M=o3ki0( zPN7bOyW$@mKGAj5=v&W zSgFsJEKzxxK6k_RWDf!tDZyKOO?xikTVMdgwlUyE;YG>~9p#NJPoukTs^x7>&%M%H zYo7a6RAFFM71sQ>3ds)KeJ4T$;avnCAr~GG6F+1GZ|2{1h}T6BkX*I};OelEHuX8R z{jLuC7j<~j37>LxcxpD%IFY3LyPZh97#mkh;p?FpIX=6+>1L9Cc-q;n!@Q5jlckmk zskHxk#tAjf$ofmU0%Z!|$`tpFM?*}_jU~+teCUY;7G7zXFF%%pe;9@3jrQH=zjog0r!mn literal 0 HcmV?d00001 diff --git a/python_parser/check_services.py b/python_parser/check_services.py new file mode 100644 index 0000000..e03fd9f --- /dev/null +++ b/python_parser/check_services.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +""" +Скрипт для быстрой диагностики всех сервисов NIN Excel Parsers +""" + +import requests +import subprocess +import sys +from pathlib import Path + +def check_port(port, service_name): + """Проверка доступности порта""" + try: + import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + result = sock.connect_ex(('localhost', port)) + sock.close() + + if result == 0: + print(f"✅ Порт {port} ({service_name}) - ОТКРЫТ") + return True + else: + print(f"❌ Порт {port} ({service_name}) - ЗАКРЫТ") + return False + except Exception as e: + print(f"❌ Ошибка проверки порта {port}: {e}") + return False + +def check_service(url, service_name): + """Проверка доступности HTTP сервиса""" + try: + response = requests.get(url, timeout=3) + if response.status_code == 200: + print(f"✅ {service_name} ({url}) - ДОСТУПЕН") + return True + else: + print(f"⚠️ {service_name} ({url}) - ОТВЕЧАЕТ, но статус {response.status_code}") + return True + except requests.exceptions.ConnectionError: + print(f"❌ {service_name} ({url}) - НЕ ДОСТУПЕН (Connection Error)") + return False + except requests.exceptions.Timeout: + print(f"⚠️ {service_name} ({url}) - ТАЙМАУТ") + return False + except Exception as e: + print(f"❌ {service_name} ({url}) - ОШИБКА: {e}") + return False + +def check_docker(): + """Проверка Docker""" + try: + result = subprocess.run(["docker", "--version"], capture_output=True, text=True) + if result.returncode == 0: + print(f"✅ Docker: {result.stdout.strip()}") + return True + else: + print("❌ Docker не работает") + return False + except FileNotFoundError: + print("❌ Docker не установлен") + return False + except Exception as e: + print(f"❌ Ошибка проверки Docker: {e}") + return False + +def check_docker_containers(): + """Проверка Docker контейнеров""" + try: + result = subprocess.run(["docker", "ps"], capture_output=True, text=True) + if result.returncode == 0: + if "minio" in result.stdout.lower(): + print("✅ MinIO контейнер запущен") + return True + else: + print("⚠️ MinIO контейнер не найден") + return False + else: + print("❌ Не удалось проверить Docker контейнеры") + return False + except Exception as e: + print(f"❌ Ошибка проверки контейнеров: {e}") + return False + +def check_python_packages(): + """Проверка Python пакетов""" + required_packages = ['fastapi', 'streamlit', 'pandas', 'minio', 'uvicorn'] + missing_packages = [] + + print("\n🔍 Проверка Python пакетов:") + for package in required_packages: + try: + __import__(package) + print(f"✅ {package}") + except ImportError: + print(f"❌ {package}") + missing_packages.append(package) + + if missing_packages: + print(f"\n⚠️ Отсутствуют пакеты: {', '.join(missing_packages)}") + print("Установите: pip install -r requirements.txt") + return False + + return True + +def main(): + """Основная функция диагностики""" + print("🔍 ДИАГНОСТИКА NIN Excel Parsers API") + print("=" * 50) + + # Проверка Python пакетов + packages_ok = check_python_packages() + + print("\n🔍 Проверка Docker:") + docker_ok = check_docker() + if docker_ok: + containers_ok = check_docker_containers() + else: + containers_ok = False + + print("\n🔍 Проверка портов:") + port_8000_ok = check_port(8000, "FastAPI") + port_8501_ok = check_port(8501, "Streamlit") + port_9000_ok = check_port(9000, "MinIO API") + port_9001_ok = check_port(9001, "MinIO Console") + + print("\n🔍 Проверка HTTP сервисов:") + fastapi_ok = check_service("http://localhost:8000/", "FastAPI") + streamlit_ok = check_service("http://localhost:8501/", "Streamlit") + minio_console_ok = check_service("http://localhost:9001/", "MinIO Console") + + print("\n" + "=" * 50) + print("📊 РЕЗУЛЬТАТЫ ДИАГНОСТИКИ:") + print("=" * 50) + + # Подсчет результатов + total_checks = 8 + passed_checks = sum([ + packages_ok, + docker_ok, + containers_ok, + port_8000_ok, + port_8501_ok, + port_9000_ok, + port_9001_ok, + fastapi_ok + ]) + + print(f"✅ Пройдено: {passed_checks}/{total_checks}") + + if passed_checks == total_checks: + print("\n🎉 Все сервисы работают корректно!") + print("📍 Доступные URL:") + print(" • Streamlit: http://localhost:8501") + print(" • FastAPI: http://localhost:8000") + print(" • API Docs: http://localhost:8000/docs") + print(" • MinIO: http://localhost:9001") + else: + print(f"\n⚠️ Проблемы обнаружены в {total_checks - passed_checks} сервисах") + + if not packages_ok: + print("\n🔧 РЕШЕНИЕ: Установите зависимости") + print("pip install -r requirements.txt") + + if not docker_ok: + print("\n🔧 РЕШЕНИЕ: Запустите Docker Desktop") + + if not containers_ok: + print("\n🔧 РЕШЕНИЕ: Запустите MinIO") + print("docker-compose up -d minio") + + if not port_8000_ok: + print("\n🔧 РЕШЕНИЕ: Запустите FastAPI сервер") + print("python run_dev.py") + + if not port_8501_ok: + print("\n🔧 РЕШЕНИЕ: Запустите Streamlit") + print("python run_streamlit.py") + + print("\n🚀 Для автоматического запуска используйте:") + print("python start_demo.py") + print("\n🔍 Для пошагового запуска используйте:") + print("python run_manual.py") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python_parser/core/__pycache__/__init__.cpython-313.pyc b/python_parser/core/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..876b1a052ef1516979f87d9cb688cf5d3109de6e GIT binary patch literal 168 zcmey&%ge<81gh88WPs?$AOZ#$p^VQgK*m&tbOudEzm*I{OhDdekkl=AXRDad;?$zz z7~jO~V%@43m(=3ylKg_0g36MN{Ji*r#3G<p$LLN+0x3yw5S0iNNSX-SfCmv7#_wv;xR1P&_|QZe8WDKcmzgwa*73m@pZZqP2NIt==gw?H+r^(r_M3C>chB8B z-#tHTnT*1~^VcumU)&`y%%3>uJc-y?`x%VejK&Z~V>RwHJI)bqoF{xgj``EVc!DIx zMIw$%M51%TX_+K-ZWohhw8U;k6OVGyUPt3Ci4wCCu<{l*6|+fTl`U*KW>dhXx3HO* z%>bL-!e&c?nyc@JV<`T&{v-b5q5M(JD?3%Q5(;Bw%M1B;s?!rz{Au(BQqpJb0=#ZBIzw2HkJDJf4>B4@ z1U;dP8vin|x&)R$Eu2eGOU^TTQWKA{AXEz0rjKxV8^BA*Yck1{lByDB&etlASvY53 zuG_A+k_4`P7{LF|pZ6aJ4gXPatsg#czTdwOGd~24UepcMwm8?%XPC7GdaU3mWk_C%2m7S04*6t!Lh*LU5|u7o7Jl0 znJBXhvx&)R&vpsQ8VUu_oaDeHB7%gII}F3c<(6T39w|@OVYy+D9^lsC$As^lJg%R2 zZQ|-@%}eg^=lYoKUh}=<@%}o3{aA>hF7#MAwX&!94t&`0wb0f>bDB08T-w-Z5%;K~5 zF2H{c7cD_#J*i7^V2Cs@B%+iOsvM>}f#Je!t!#sB>#qX%cObm)Lkv6!zQKzRu5Stq ze{o}ANN(M-YzTg73eYUs6JgSs{LHpIqgB{lMqx*mPAzwQ)7_$oy5Z9)?WkYl30(SYCH&LFqa_H7O{}rgIuFk zCHRV@z$;WrwihP}{ptx-d9G@aR8+L}`0lFLAnZ&K@O18r0I1hnaV+-qHMQ12^TJ$q zS=bk8g=;rxwO*z^0p_2z(gY&u7;jLJBE|3?I|U2aG_XoM*NMdpR9iVzA|+`g9ssBM z>j2#%ag&n4t&K|dgWCk8Kimt!eWLKoK3~WITttO@1uZ;WR5EBVV%>=L=@yJCvIzK3 zF4j~O_e2zogKA@J_E7Uki*IQyd2TdN@=Jo+-g}_&!R&>mb@S6@;Xoug?(lylKbHol zO^+@`-2#M;FQL;DsN_=AH#8CYf&js*e2nF+fWoif5$b~gAo+Z7&3_EofcG*Ss7ty6Pf2HBxyVK|bRI_9FHlfnbjjtw1y$8Blb5TUn~ ztEFcSL>q@#GphyDC79e%b*E(r^`h5L&$Ovhh4P80uZ@y7U>yrT_cp*P&$8?jj$?(V zBEzb`GeZG0^c%B%Rb;r-Q!c^2y~+Tr@i1Ja!yZZq?7>wAASQ5_r3BCJUu6Jd0*C3? XBaa^Wb&veI#|V0iP~r&(78U4kpZbul literal 0 HcmV?d00001 diff --git a/python_parser/core/__pycache__/ports.cpython-313.pyc b/python_parser/core/__pycache__/ports.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..062c066c2b70029d7383a16e48ed7f1716c4bf47 GIT binary patch literal 2572 zcmb7FOK%)S5bk;G?8|E#+d+wAV89NrpjaR|LPQ8Dv6X{uOym)W!$_m??s&b)W@qV{ zjbg+hu?Yx#fQyAWIS~gEiG$QI9U&oc%FSqvxKh=#>wU;pa389>tGlbK zzOMSZl1e2Av@^f`Jo6+%$X__AHJFQ5`2@N}Vh~CU$&kmSQJKo43RQHRD`V=_F5FwyEdP%P#ew#=%_q4G?Up z6^a@T>@iybfNmj7Y?rO__;kMDSS8z^;abV2_BD@d)B$jcnd&PDA0?1Duc#mvNlr@3 zW%M2%AhZYIvxhn$zrr@zHe1ozhR#;uigmUMSFHqd`iSk@m*56x;yy_$T=ks7G)12& zW|N2JbzSEp!{^P9ASBQHz`p98{mdM3ysN%jGE1}YEJg4Y1GX~L%?dN)QpYR-4&GpC zmPf=k-dTrdP-xoVmI^-LO|qwvc&Y+J!sYDrGs7K+jhJtcPxHZ7kYPKJacepRxC7x; z6_9G6U9ZQg1LC_V04BiZ7XW@P98J&^SWGLl9Xi^Bq7et$0U939Ilgt>E|eYK(-6vm z_BlL;8AiKNpv8%FipMOg2tZpFPgvG9H(Q1`ws@OmeOk5))s+s*n$Ai%}B(>!25$NuXh;C(a-F#qHP*YKe)+4s;#cHFai_7Cb zjE6f1>bojvD7+GHJG@%AVCAT4oy13IX;67FsNnda)f%oPP3^Fg$bnF^KwJ$q-Uc;Z zv)EeCsiw7f)46sdK|6BEbQ@0^zDw<#BZ|Eb?kK+t;^<-zZi`IAJl$p+!Pi)ok01$m zfE^Zs+al+9+?~1tY-r`PGzr$8Sq3lSm3M)5YsPDZaF8H}B=#9NR4ec>vD-cSx?^R5 z5~h(7cyB{&gUxF%!Qpz2XJnYx+F`WR3ybV~2=gHj-8_`%7R24++}9!#NfmeG`Q+{5FnWM$tk?{is8M zM!jVaNJqmpI=a*KQ{UY_!7v;BqWiUhXj^#qLj{~^!`zWonH0oKO= literal 0 HcmV?d00001 diff --git a/python_parser/core/__pycache__/services.cpython-313.pyc b/python_parser/core/__pycache__/services.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d655af45a0baa277c48328bcd3dba578ca519991 GIT binary patch literal 5502 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 literal 0 HcmV?d00001 diff --git a/python_parser/core/services.py b/python_parser/core/services.py index 85b2162..0d3f791 100644 --- a/python_parser/core/services.py +++ b/python_parser/core/services.py @@ -48,7 +48,7 @@ class ReportService: # Генерируем object_id object_id = f"nin_excel_data_{request.report_type}" - # Удаляем старый объект, если он существует + # Удаляем старый объект, если он существует и хранилище доступно if self.storage.object_exists(object_id): self.storage.delete_object(object_id) print(f"Старый объект удален: {object_id}") @@ -63,7 +63,7 @@ class ReportService: else: return UploadResult( success=False, - message="Ошибка при сохранении в хранилище" + message="Ошибка при сохранении в хранилище. Возможно, MinIO недоступен." ) finally: @@ -86,7 +86,7 @@ class ReportService: if not self.storage.object_exists(object_id): return DataResult( success=False, - message=f"Отчет типа '{request.report_type}' не найден" + message=f"Отчет типа '{request.report_type}' не найден. Возможно, MinIO недоступен или отчет не был загружен." ) # Загружаем DataFrame из хранилища @@ -94,7 +94,7 @@ class ReportService: if df is None: return DataResult( success=False, - message="Ошибка при загрузке данных из хранилища" + message="Ошибка при загрузке данных из хранилища. Возможно, MinIO недоступен." ) # Получаем парсер diff --git a/python_parser/docker-compose.yml b/python_parser/docker-compose.yml index cee6775..919ffe6 100644 --- a/python_parser/docker-compose.yml +++ b/python_parser/docker-compose.yml @@ -1,16 +1,32 @@ -version: '3.8' - services: minio: image: minio/minio:latest container_name: svodka_minio + ports: + - "9000:9000" # API порт + - "9001:9001" # Консоль порт environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin - ports: - - "9000:9000" - - "9001:9001" - volumes: - - ./minio:/data command: server /data --console-address ":9001" - restart: unless-stopped \ No newline at end of file + volumes: + - minio_data:/data + restart: unless-stopped + + fastapi: + build: . + container_name: svodka_fastapi + ports: + - "8000:8000" + environment: + - MINIO_ENDPOINT=minio:9000 + - MINIO_ACCESS_KEY=minioadmin + - MINIO_SECRET_KEY=minioadmin + - MINIO_SECURE=false + - MINIO_BUCKET=svodka-data + depends_on: + - minio + restart: unless-stopped + +volumes: + minio_data: \ No newline at end of file diff --git a/python_parser/minio/.minio.sys/buckets/.bloomcycle.bin/xl.meta b/python_parser/minio/.minio.sys/buckets/.bloomcycle.bin/xl.meta index d9788f68afc7428d0d870b20e86b7ff3dd047df3..60320f33e0b12d1de769c05d89eb2441a5f3db6a 100644 GIT binary patch delta 444 zcmaFP`kZxw2G1(<2^tb|M_4K*r?XBpF&0>~ZK=2QZm&1<)MOKW7&+ViXZ*)A(!vF>?%acosic<4R7?$Lv zR+OCOIla8NB(bO@HRU)DD@aAgdJTEDl=SWEk}H#QQl0a23vyC{vUeB+;0hE2#DW&p z+aUNo67u$P2<{09!M*)(t`duw%e6%au7g-vVjqHABew3_9RzoWSZ3rz1ow;7xt}_4 zu5vg3mcJ?xZZgoN%Etx$w(W;Ys|0fLw;n-od%0hn^M`ZQ8JXWFSs=JJ*3Dwv2yP{7 Pja4|Dt06D64RFs-m!muPS zwW8!K&%))!C5c5PsVT>KSV1Z>*4*3A?SA;hy5!2_oK)xh+=84`pzIw60l0$O)|{^% z*Y82_%en4_#3Q(yxu&QtLvY`7-{f8b=ibrgzC1S^!A<9>*~x_9F6O>B%?ZK1&-3=> zQ#kjoGJp5z>=+grD&sxaWBV1Q4#g$IW}Ku>~%B&zn~w-? QGcW(?Gz51)uaVDF0Dv2$p8x;= diff --git a/python_parser/minio/.minio.sys/buckets/.heal/mrf/list.bin b/python_parser/minio/.minio.sys/buckets/.heal/mrf/list.bin new file mode 100644 index 0000000000000000000000000000000000000000..a3568729c698aec1d183514222bafc72dafa7007 GIT binary patch literal 4 LcmZQ%U}OLQ015yD literal 0 HcmV?d00001 diff --git a/python_parser/minio/.minio.sys/buckets/.usage-cache.bin.bkp/xl.meta b/python_parser/minio/.minio.sys/buckets/.usage-cache.bin.bkp/xl.meta index 7ff1b23b53992c162455760eee3c1b082f28dbef..0a02b2607d5dcabf77aae8ad6d9bcd9da7d1d07b 100644 GIT binary patch delta 357 zcmV-r0h<2#1n&fpC=9AMjcqCt!~`tgAGVP+GZ0ruuzcI5PdTG}TvXj$4}y_*UMIY& zP+@X(K~rgZWpk0y0KBAAX?kVR0KBD5RB3Hx(->c>H;rv75|R8oATeVxW@RyBH8(af zW;8NnHaR#lI51-}W;QTmF=SykGm}^WE`K|`rV0Upq;7R=Y{cB`)`)D8RgA@>6wbWc zb1Z7nULQ~iZoUzdP&-jl;n120D77#B1ORmf0FsI)EpQ105CBM!gaqTrAh+~mg8tA@ zNb8wX>&ZoNOFZATfmHsrviT+Km^pYqVe>!FzQw(CA+r&jmAM4@8f&udW&i&x3Tm?U z|0n;G7P DiQk%& delta 367 zcmaFQ@{?tP29M&KiiJwGM_4=#ZoNIx#8|+%e1q0TA2-eR75w3j`@FLzmdB|dTNRL4 zRN@$%S(REm@gl>qB_I}%Ug{f?nVWi9A|7JM#6LC)NoFPn=1Hk3Y37C|mIju|<|&C5 zCW(fIX+}nAmc}N@lOq`Q>i_y0bu%_D$t%stIr2;<^5jJKIPUPpuP>M_C!Ba5XLQ%uCB}S>l(No4QbcrC(}AiF0LgPU=~n z1*?1#i%UWaQW8s2kMpoH071r@d;57-s~uP!oSj+Vk(!v3nU{WOsdHj-Nk(eZ>f*Be zlXZJez@$5oj6+Gb}30n9dAh qFfc4kKD1CDq;n#&Q9x4|fF>|7urLHH;b2+A#}HcL$d${KAqxQ7^^vLo diff --git a/python_parser/minio/.minio.sys/buckets/.usage-cache.bin/xl.meta b/python_parser/minio/.minio.sys/buckets/.usage-cache.bin/xl.meta index a52d8cd1249962d0b5ee4a682dc1a41c82b68eb5..241fe0b2ed958d3e7cc7feef3d76e00242d96cff 100644 GIT binary patch delta 357 zcmV-r0h<2#1n&fpC=9AMibtHs#00=C)~b;-GZ2LR9x;(c>H;PA`$C3OzATeVxW@RyBH8(af zW;8NnHaR#lI51-}W;QTmF=SykGm}^WE`K~A>yH6}q;7R=Y{cB`)`)D8RgA@>6wbWc zb1Z7nULQ~iZoUzdP&-jl;n120D77#B1ORmf0FsI)EpQ105CBM!gaqTrAh+~mg8tA@ zNb8wX>&ZoNOFZATfmHsrviT+Km^pYqVe>!FzQw(CA+r&jmAM4@8f&udW&i&x3Tm?U z|0n;G7P DV&R`q delta 367 zcmaFQ@{?tP29M&Kim>CqkFb=zjbff?Vk~fby>yA2kZbqulhaGTsmEDNERRz^wkja8 zsKhZivnsWC;zfpIOF%3jz0@}(GdK0JL_EZhiGOSqlFUpD%#%`6(##D_EDbD^%~KLB zOcD(Z(~OMLER9W)Cr2>q)gO!d-ptszB(F3l=g2de$deP@`sLPl%YI*N zYVLQsHhbko$EvzX^&A>o_5ZRk9A#yg!qv3IGcPT_Wr<&6Zt6n)m42xeCC-(}IjLuP z7Oe6~EG`KxNJ%V7J zQ?e6vf$9@G7A0p)SX5kfiJ`UZ-J<+r=0#=242x58fkbgt@oWZ0MxbdR%&@2|V>&a4 q!N9OE`Ordrkj{z7MgdJ>0GhzSz`_u)go9-bA46z~BUdg{hAaRR^ps-& diff --git a/python_parser/minio/.minio.sys/buckets/.usage.json/xl.meta b/python_parser/minio/.minio.sys/buckets/.usage.json/xl.meta index 730862b33bad405b7c19a40803a1ae642d449ffb..2bb41d046f9e37a8c9a916b4ef14bec77235a207 100644 GIT binary patch delta 187 zcmaFJ{g8Wt2G1(<32K&;jbYHVbYWRPZRmSUP{nKs#wQO;~(*}05H z)>-HD80&X3HZI94&B-~+68hknrP@1-h=>D49)>0}w&)#QGhaAFr0nv&qm^YZln&NR nUc)FMW*%Z_YGq<-Wo)WvWN2n)VF)CnlqNee3vYhQ_=On&@~=pB delta 186 zcmV;r07d`d3*ifpC=4O&cdBoGh#M1GB{;sWn(m< zcFt&l1)9#>o3-EpfuwGAY;45@Ro+qnT9A?V>rXCNzsYzy$OImIA)Y?w1*RiE6 o3X`k>7#1~DGBP?aH##*rE;2DPH8e9ZHaJ=$lR*O$v+V)&1J!6r4*&oF diff --git a/python_parser/minio/.minio.sys/buckets/svodka-data/.usage-cache.bin.bkp/xl.meta b/python_parser/minio/.minio.sys/buckets/svodka-data/.usage-cache.bin.bkp/xl.meta index 306e110f18f391e66454496d8b7180436508b955..1f318434f5ae72bf7db6f3c6a5e5b843c7143240 100644 GIT binary patch delta 290 zcmX@Zx|el=2G1(<_8DnCM_3LxX0uK-F%~GS`s`op<@a}L{<&l^=FqDX%j48JR|O;% zl{f}xR;3nCyvWG81jGW;OMOE!b5k!%#6t|3_{T=U%rMQ!C@D4BB-O$&#lpxU$;=?h z+%&}`#mL;;GAY$!as;EE&HbynT#SuN@=9}ZjxuUi3#RT8*vFJ>bAjL7`Q_y>micpBn6-Z6V-Ah2`hQ&*G#SsbGnnv9KE$XZeQK3YVsS}mK}upt>Tw=c1|Y~- zuOZJKvT@I3My4{ig52hr)gVzut&4>bq6`KL)ATfyeJ^qtM9VgOXmVk;V(4K^d?5PZ ioxubF?jwwU4&_z^9bruSY+|FAG+RV(2II3+fpP#XTx#(E delta 305 zcmdnXdWLm^29M&K3c<{EM_6<-J9bYrF&6Ms;9L?@?R|4;Z^YWV?ft0}%j47~Rs|#$ zl{f}xR;3nCyvQiA1jGW;OMOE!b5k!%#6t|3_{T;e)yOo_&@9c&G&L#FFgex0!ooPo zz|7bn%_7;-!YI{zas;EEjh{194`bt!ywaSUql^~%>+Ms@cK2occ-4^Ux@YPK^FKNB zH}+YsI%XlSQtP^>h(lwm{$CdcO-5G^1{L1PhZt3)7p(G0EG`KxNJ%V7JsqO#EXoaOF%3jz0@}(GdK0JL_EZhiGNJhm!y^?rr%UBGfXowN=i*ONwqLc zu`seoGBZdrH%&1~F)}x|OiHzwY{;nQvasx2MkDL2bITRxMld!m$t%stIm)P6EttAX zU>{Si%>{mQ=a;Wojs!jPNm#+iTISDjVb=PMk2y59>i>0N&}2Nz&S1hb`4FRu^r=-o ziNz(M1u2OosmFO(8Gs;Ty@ot{$i_XB8JWu53UZrgR)a(twJsJ$h%y)~Ow-d)_Pxkq z5G~vAp~;2WilK)w@qy@rcLoy#xQ{UYIh0!wbc8YOvx$vf(rgjE8H~?P1ce=B8ejh=&+5@sH``2u8K~C8;He={FTpjZ6~_&C<+F zQ$<0iLu0G{Ul#^VMpq6772c*Lo_T5cEld0o zb5mCrm*uBqC+beV#wZ}YV3ki|aY<-FN@7XsaUNC%AjnvAZ$J0H_QuJKOl6@L3nLgA zRN@PAFEKRFtY!qsFDlEJ4rDA$J}kZI|Z#{}GvgB%h9fh4C~3=M=}Lfmt~hs?@gN;`*{_h!By-g{Ha zbF(xxMLnV@+MAl9$6x$Bo}vD;UVgs1_i^pcpI67zKP?}h&=)ECkY4z9WDGn=->Pth zX7`A?bW@T4PaVlJ^2am9qthSuALNDW-+ABXR~ldcmN8RS$E9~OrWS5GwU;p$N@xgQ zP{f`jiqnF9n&4!FgB|*Iy415Ll-tX|5A>dmcj!A|m@z;HKb(XiAMZS;U;iFHq|Vb( z7?JB+nt^P1Ud^5c15g^^?Sp>AMh;BL^z#S zvoXMP2~mPVJCWc8QxLeA&=jL0D}c7dv)sPv5-lf)1f)lQ0ME0K2?FFgUv{zU{JQaM zZTq8No*mrpKB2cqPS3IqFI+gbcki9PfAdNI=6?U=@$S>NcQ1eX?uMcN{m+koT^H|u zw#95f9}^8G8J%ZLAGU}A0v2YHTMRHwi188}Fi9pZEY;!_C2z2D%1~oMsh*RWc?Ltm z3Cf)%I8n`uQ**1cLKtx8uyP@U5)Gp6SowRHkkSbaUH>)D2CWLGwenQXb# z)wpuhS}dlCfL)1)0-9k)^{&Pi3}vVdHj$aj4jNUSRk|)}R;?bWN^6Z=)N3MQveYOp zSJhgZYpUsBNkfI)Mqz=+)xn}^`M&B%t-wn+2GuwgSGBe!IqYy*O63-vw%yCvX*;!O zWfF=E*+N8dwCrjuBRKL3X%y^x$e&D$)XT9PA7K*_E@7}-GA<^gu}0X;00ceKd4`N* wp7DTBW>Ln_CpVM71X|=^uFW$&kNhIoN(KMc5{+p5OzVmyN+Qn-B2m5e0S~k~f&c&j literal 0 HcmV?d00001 diff --git a/python_parser/minio/.minio.sys/config/iam/sts/SIXCOIEK8M17XZ3JTN2B/identity.json/xl.meta b/python_parser/minio/.minio.sys/config/iam/sts/SIXCOIEK8M17XZ3JTN2B/identity.json/xl.meta deleted file mode 100644 index 7a8c8964a2435a21732e2629553dae46b3ed00b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 910 zcmZWnPi)gx7`NL}PDmg)R69&yB)Bx-KXK|rToT)~PGTo%oIj0_GW+>8d5Pl~`?)kh z2$fxT=?+Yq1Z-o`ZxCyu*9n_ulW1zVCa@ zB7c^q=BeitMf>yf^z_0P)05PD>(x?w;Y8uHJGZ9`r&H&S(~A^+NasGCm?Iz3dv(5K z_x_+xJ=ByBsS`y(!Sp2h_3q-+uSy^Puv94ieD3v?Z&Z+VJ45=B3iNn0sK+YERnZu} zq=-F9G|z$CG{Gq-#Jltpxf%^-lqY2?z(zC(cj<5AP&KVi_-q!&{BZXL{pWY_L-uVt zi6e5or<-U1-&XTjhuEr)!kvTd!~l6{m_QzefoHiSaFGWSj)kr10uCZL!`8y!&V+C} zzn`^P!2+C=-sGjEAc^dzC_*RA0zR3tR)D~N4~9g`!wF1!v~T&oi-3jE(7W6Vhu+s) zN8O!cUmpGRTcu6!OuWc-59j9Ye|~=d;K7N7f13ZDx%XrGqWe+*ugWj~UOP7T@Ob_2 zPoCanwqOtv4JN}aGa!HtF+i3ZGMSr<1po}g0vs_Jrm8jNlBO0Uom*+PguH3+IcAv& zA>rURkWCwoPz!;4x17_j<5U&1HIXa#8U^3a7ll=$F3Ibr8qH{7Y-$eskT^4Nl<(TB z0F_W)tBq^hI?_VTTNi<>rL?}^tjqcIr5Loq8!ixxVyoGY!DhAIRZP~sS{-){-E=k@ zJ)=-plcP#3FsLVE0o??g(NhIo$&L;A1_G;BN3Dj)YP}({8*XGZ(%sf7=i7*w*w^ij zk#0Fnn=jjiwjo8>jgonztE_Bw2X;lMr*a#LXfy|X2V;3GLseJCygRUswQ{@2bEaEj zvmHL6m`16BHq5oPwwxsu!)+f0vuTlfd6pLwtd!tWCd*}5HX|fkaaXW~Bhq<>jANPc vt$@s;7Q%qs%>I()kb}9k%tSuF;ZY;U}iYRz`$6+%*=R1ZTb-b1~hP4B3|)cL+$RBM_5?aZ+yha#=v-#(W`k$ zNM%7P#Y41$Y1T`;vSadF8kIwCM>LkDBaO3$jrno^pE@9zaKb4_;4NzZ3o z?3(NgBK#PZyCypYXI7#uQa!K zBI8OB(={Y9z4!o_3DRFY@gk$~Dv*RDoVx_X0tzqn4av++h5Kf?Z)!HAdsmt}t9v_w8_vDVi5bD2 n%p?4a2f;nhDmhZ0pH@_2eZ7!GZ`1trwAkvpE#ef%o{{%=^B__vXfgZwvwl z*aQGp91duC7OfHR&-r+C`b7Uu=s2*P{hj(vcmTi+cy->)REq?*ulpuvZuP;ak&ORO zHREwfw?-aL#v4C=M#PRVda`%ysq1+HN9DW*ml8N-ClM?s@TIg=BU^xv=S5P@kqYE} zafz}fT#2Pi%7C&mg>)vC6xxIx8zwR+Pu~up&8N)|U~|=ei0+rBjrestm5~&(?`Ang z7)n=Z{Y^zsBvsM`No7P=k<5WCsYJ*jhAb!3OJvZSrFz5UocyP;z=a(4BcDGU3WYBQ z5yC+n2#`=9h{LnkKXbl|HLj&Hf$<%^M#Z8mVZ_Rc$+EQ_4u1W;yZ7za!QJsM*R~@&=R7Z`Lov^hXbK+ceLkHY8h_>8bAk;Qcr@HF zlj^LtV2Vf~EpJC86&9;vnY?#DTb)3ZWsBSbdFOW7KU(Pa=iLkUPpzfrq~aBVxW)W> zJBDz9G}dTY%gv#I<9h}!JTPc&3*0S#H#F)n$`mZ+6rN~}J^>JNF*|@!E-X5106+_` gx4bs9`L`5T0bBt9CzvvaoZZ79%c8@PGcRuc0qWJ|)&Kwi diff --git a/python_parser/minio/.minio.sys/tmp/.trash/aa8293d8-dcc1-4475-8490-1c6a8e9f19ad/xl.meta.bkp b/python_parser/minio/.minio.sys/tmp/.trash/aa8293d8-dcc1-4475-8490-1c6a8e9f19ad/xl.meta.bkp deleted file mode 100644 index cb23c1858f0750de4c9ab6382b5905529a56ea84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 702 zcmZXROH5Ni6ozL)i;9h6!lH%^7&VA#K&k?XCKg&ELW@ZOF)_KBPKWl&eR*eE3M@>a z5u+?5N{A94Ef;yNOh{aqK(MF_M1inqVj5+o3s-J@>)b9_=qyhDGxPm(=A7wht}1~b z54->X#`5xD`tWGF5d5_TbwYBKRNZRsPvT9^;uGCVh6wDxEOPPA9G1TJU6zEq?8 zf2-kki+Z|nsA-|0uFUgh;ll6FBWx`5*n?eCNQL7b>@|ZAOnPvgU+g98fS2bm zX3|R-^7qjAvzS8`6;XAF3M0CLBrYUTA&wwoC~aYSgyh&Zs`ne*6Uvl0t7{0Ub&?aE z7~#r5B{_+L)qxs*Dpbq}b5N!eBqyV*;kfnQ zs=CM84daFqk)&l<-cT$YFgAZ!woZ+Ex>v0?ZP~=u$c?r;9}eN7{4b}U>@1tF_~iyi z;N}kCw)Gp0N~fAId`KpQ10E+J`!W~Jy;^IZ4YOf5oK)}?}xm!S>NdS%P@Kp{0p>gu^6}DX&mOMIbRuB*C14AghYVRGl+IXM{-CQ#gDpMSIt- zbfi=YQ&9@WgE9}amyQ7lKq?v@g-QI}1aD^!3K(fJ=K-gA?In!X0hEdX)Z~G?eE<}J z64(AqwvWI*7`HuoKji%$*fnHbT0E+~yZ`B}@#<@OaicIaIDPTj-qGZl2QBmV(t5A|UB4e95PIlAY^@$lQV|klDWB>&fOk6Fi3*1bBJ@Fd% z|5nrO7WHIK_95fh$gp>Pp!Cjx{U3~;aSyJNLMj~dV6PQ?V8VmX`^8qW3V3;*)F?p` zg`9JXl=Z^NYQG_;Et6M}&U}VUd*PHNJ@qI==hM>i)7}-BHEkVKZKtNC_;$iuFUn-Q zn+Y#r$lpR^FQZObR7BM&Dvam~lDLpWg*bzVp`?xJ21&CGRBt!AC$v%EDz6}<(nU@+ zVT4NpCFC>;mIo>bc42}}mR8PUmEWZ>C*w1Efiz7LF=C>s6swpK=A=v~NFI$Whhz39 z%bVBx_QIH{7?QLIi!S5~2hH_gwyiT`p4-dzhmKU|R^Nk$$DfYi+{~|MpYJ?2SNz)z zj>GjG!0l)^Ym_Fn)AS*k%+QD$Y)0vKPx(lcRkvV?ymJgs*CNUqG~N$+Ad>m`H*(13^|5k*PXogeHSX_v1L+6Q`{! zw;JOrh4BalV?mh*+DZoj1Rx#>_rp>A$^sv492PLrWX=Ol^V$m-tpX_J1E|Rz18o50 zf`Y1jHyocqURTU9^0C|dGq9`MzA%46+Z_7x-hBH#Ilq<@>YBQCZ+HLbxuqJbUy!ZQk-}n2ykMFyfp$2iR z58J{pywcZ)H&5Sb_G5d#cgMt&yVq;a>dnBw@SE@WK@8u-lQ$c}LIvV0Q`AIpW*0m1 zAf4(>ZKP6)(d<95ym~ytpZ|Opj>op{UlSg2QbH~1_(M+0+J8K@%1Oz*aux1iNFH6% znhfW06qiy=tB$XYkn4&`)e4;a?l}3BfB_ zK`BH3HLF=@f&7BG^lCm-Ry0KqDVhZh4XEg#DjE#Qzyi&HWmKUPTQH3qPbD1%X;#QW zk6#CsimFJ!QgrR?jHzo4RI&7akfA9i#(*eYoMs{nh(zLaRHmUUMPf2Uzva2@D@zCN zZQt5i{DChuw5qCZ1`6SCJ6{hEe33t1{{3O+(DUKlqc4dU(c-D~U$=jzHa0#j5-KpQ zLIt^k1WQmPMTbZxM9~68v1E*;ht5!8k_=OEa_ABfB=q78lq_>ZuWA;-MuNl~G)&~Q zg^)o)hAOmR78tXL@&Xa;WeU0lRJ(Ts%fzFxcqHmmIp{w;txf9$Yri2#6syuK^d-YS zP%uFWx`B&?Ij76Bz-cbQqU*i_lTectt<<5@;ihfz98gp!|0}A+LwVmKy;?o3=+Wtk zXt&wxo-=-9XnOUM0m}AElbmpY<9IPlQqiQC;8S8)%q9tz3U*PV%f+JNI3iIK+j%J5 z$wQo-i2C4j6w@N zr|M{qO9)&}6vh&~*kLonu+j9P1)(Jr@_uZE<( L^>ZfAUCG)XJhJg^ diff --git a/python_parser/minio/.minio.sys/tmp/.trash/f3730b42-e1d0-4653-b974-5938ec8af694/xl.meta.bkp b/python_parser/minio/.minio.sys/tmp/.trash/f3730b42-e1d0-4653-b974-5938ec8af694/xl.meta.bkp deleted file mode 100644 index 082dbdc9b72f492ab5a2e1e8439d49d0c5730c09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 633 zcmZWmOK4L;6rCY2T1u3<5Q?k1Ft&>{B|qb?X%aBf#7YtoH)T4RCeOZ4cr$qf-WSlFZLI7A)*TxQqsCIV7qdYh0x*$6zxKa6r7hu5goXfb7$^3mviU(q-O{M z8`uH>7Hu}zb}qIDz&~eaaQbZb_9yLmTevIynt;au+=Q3s%~UB*VDp;i%FN9!IAz2l z|5MFKMAX^?`q=l;$U)*qZQ;uq{pF3pCs7=dvMOAP;<%L(U^$8>l46-`13sP?F(pHa zkoQGI%Ia_>oGi#a%E}bdSfU`)I$X72G=;MCO%GapT7M6=)~tunQE6I;UpM0^Q6@)j zmg9t>WQkT@7hSTbh^k9e7||3YaUh8bab*xgZGmY8((6rAt!i>k_QR0xLI!)0#~Ta; zf*1V=VL$fyNWkaE!CCB`8EavcYbngd_>Nwod|nbUVxp?JRm=!;QKk_jH}p=fVt?2v zr*=nR#Z(HC)ZPpFKmXo8{CaSFe|Y!m-uTZ^=dhbKB8&nNqaU$_qiuxSSm z`m1J4nN@3M0?DM|UQLi93zx7&-Z>txO(M$Dd2WHcb=a*R&9%Doj@rF*>&ZDWe~BP& zF}u+WBb+1Eb*ihGIn;B!VBp++gO<0!9sQf3Qk$Vuu#}N`qGkFBK*+_c0EV7hv{?Xv i2Ht46EoS|1DXs#z0ssP-GW&$qNswlt{_&BgxBdWD0qPI{ diff --git a/python_parser/minio/.minio.sys/tmp/989d8b07-b593-41fc-9dbf-831f9b04f598 b/python_parser/minio/.minio.sys/tmp/060ca61d-ef6c-4011-9a9f-d083313258e8 similarity index 100% rename from python_parser/minio/.minio.sys/tmp/989d8b07-b593-41fc-9dbf-831f9b04f598 rename to python_parser/minio/.minio.sys/tmp/060ca61d-ef6c-4011-9a9f-d083313258e8 diff --git a/python_parser/requirements.txt b/python_parser/requirements.txt index 2e74635..6f0b33e 100644 --- a/python_parser/requirements.txt +++ b/python_parser/requirements.txt @@ -11,4 +11,5 @@ requests>=2.31.0 # pytest-cov>=4.0.0 # pytest-mock>=3.10.0 httpx>=0.24.0 -numpy \ No newline at end of file +numpy +streamlit>=1.28.0 \ No newline at end of file diff --git a/python_parser/run_dev.py b/python_parser/run_dev.py index a8a03b3..bbeb465 100644 --- a/python_parser/run_dev.py +++ b/python_parser/run_dev.py @@ -4,7 +4,7 @@ if __name__ == "__main__": uvicorn.run( "app.main:app", host="0.0.0.0", - port=8080, + port=8000, # Исправляем порт с 8080 на 8000 reload=True, reload_dirs=["app", "core", "adapters"], # Папки для отслеживания изменений reload_excludes=["*.pyc", "__pycache__", "*.log"], # Исключения diff --git a/python_parser/run_streamlit.py b/python_parser/run_streamlit.py new file mode 100644 index 0000000..7c63763 --- /dev/null +++ b/python_parser/run_streamlit.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +""" +Запуск Streamlit интерфейса для NIN Excel Parsers API +""" + +import subprocess +import sys +import webbrowser +import time + +def main(): + """Основная функция""" + print("🚀 ЗАПУСК STREAMLIT ИНТЕРФЕЙСА") + print("=" * 50) + print("Убедитесь, что FastAPI сервер запущен на порту 8000") + print("=" * 50) + + # Проверяем, установлен ли Streamlit + try: + import streamlit + print(f"✅ Streamlit {streamlit.__version__} установлен") + except ImportError: + print("❌ Streamlit не установлен") + print("Установите: pip install streamlit") + return + + print("\n🚀 Запускаю Streamlit...") + print("📍 URL: http://localhost:8501") + print("🛑 Для остановки нажмите Ctrl+C") + + # Открываем браузер + try: + webbrowser.open("http://localhost:8501") + print("✅ Браузер открыт") + except Exception as e: + print(f"⚠️ Не удалось открыть браузер: {e}") + + # Запускаем Streamlit + try: + subprocess.run([ + sys.executable, "-m", "streamlit", "run", "streamlit_app.py", + "--server.port", "8501", + "--server.address", "localhost", + "--server.headless", "false", + "--browser.gatherUsageStats", "false" + ]) + except KeyboardInterrupt: + print("\n👋 Streamlit остановлен") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/python_parser/streamlit_app.py b/python_parser/streamlit_app.py new file mode 100644 index 0000000..98c4736 --- /dev/null +++ b/python_parser/streamlit_app.py @@ -0,0 +1,402 @@ +import streamlit as st +import requests +import json +import pandas as pd +import io +import zipfile +from typing import Dict, Any +import os + +# Конфигурация страницы +st.set_page_config( + page_title="NIN Excel Parsers API Demo", + page_icon="📊", + layout="wide", + initial_sidebar_state="expanded" +) + +# Конфигурация API +API_BASE_URL = os.getenv("API_BASE_URL", "http://localhost:8000") + +def check_api_health(): + """Проверка доступности API""" + try: + response = requests.get(f"{API_BASE_URL}/", timeout=5) + return response.status_code == 200 + except: + return False + +def get_available_parsers(): + """Получение списка доступных парсеров""" + try: + response = requests.get(f"{API_BASE_URL}/parsers") + if response.status_code == 200: + return response.json()["parsers"] + return [] + except: + return [] + +def get_server_info(): + """Получение информации о сервере""" + try: + response = requests.get(f"{API_BASE_URL}/server-info") + if response.status_code == 200: + return response.json() + return {} + except: + return {} + +def upload_file_to_api(endpoint: str, file_data: bytes, filename: str): + """Загрузка файла на API""" + try: + files = {"zip_file": (filename, file_data, "application/zip")} + response = requests.post(f"{API_BASE_URL}{endpoint}", files=files) + return response.json(), response.status_code + except Exception as e: + return {"error": str(e)}, 500 + +def make_api_request(endpoint: str, data: Dict[str, Any]): + """Выполнение API запроса""" + try: + response = requests.post(f"{API_BASE_URL}{endpoint}", json=data) + return response.json(), response.status_code + except Exception as e: + return {"error": str(e)}, 500 + +def main(): + st.title("🚀 NIN Excel Parsers API - Демонстрация") + st.markdown("---") + + # Проверка доступности API + if not check_api_health(): + st.error(f"❌ API недоступен по адресу {API_BASE_URL}") + st.info("Убедитесь, что FastAPI сервер запущен") + return + + st.success(f"✅ API доступен по адресу {API_BASE_URL}") + + # Боковая панель с информацией + with st.sidebar: + st.header("ℹ️ Информация") + + # Информация о сервере + server_info = get_server_info() + if server_info: + st.subheader("Сервер") + st.write(f"PID: {server_info.get('process_id', 'N/A')}") + st.write(f"CPU ядер: {server_info.get('cpu_cores', 'N/A')}") + st.write(f"Память: {server_info.get('memory_mb', 'N/A'):.1f} MB") + + # Доступные парсеры + parsers = get_available_parsers() + if parsers: + st.subheader("Доступные парсеры") + for parser in parsers: + st.write(f"• {parser}") + + # Основные вкладки + tab1, tab2, tab3, tab4 = st.tabs([ + "📤 Загрузка файлов", + "📊 Сводки ПМ", + "🏭 Сводки СА", + "⛽ Мониторинг топлива" + ]) + + # Вкладка 1: Загрузка файлов + with tab1: + st.header("📤 Загрузка файлов") + + col1, col2 = st.columns(2) + + with col1: + st.subheader("Сводки ПМ") + uploaded_pm = st.file_uploader( + "Выберите ZIP архив со сводками ПМ", + type=['zip'], + key="pm_upload" + ) + + if uploaded_pm is not None: + if st.button("📤 Загрузить сводки ПМ", key="upload_pm_btn"): + with st.spinner("Загружаю файл..."): + result, status = upload_file_to_api( + "/svodka_pm/upload-zip", + uploaded_pm.read(), + uploaded_pm.name + ) + + if status == 200: + st.success(f"✅ {result.get('message', 'Файл загружен')}") + st.info(f"ID объекта: {result.get('object_id', 'N/A')}") + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + + with col2: + st.subheader("Мониторинг топлива") + uploaded_fuel = st.file_uploader( + "Выберите ZIP архив с мониторингом топлива", + type=['zip'], + key="fuel_upload" + ) + + if uploaded_fuel is not None: + if st.button("📤 Загрузить мониторинг топлива", key="upload_fuel_btn"): + with st.spinner("Загружаю файл..."): + result, status = upload_file_to_api( + "/monitoring_fuel/upload-zip", + uploaded_fuel.read(), + uploaded_fuel.name + ) + + if status == 200: + st.success(f"✅ {result.get('message', 'Файл загружен')}") + st.info(f"ID объекта: {result.get('object_id', 'N/A')}") + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + + # Загрузка сводки СА + st.subheader("Сводка СА") + uploaded_ca = st.file_uploader( + "Выберите Excel файл сводки СА", + type=['xlsx', 'xlsm', 'xls'], + key="ca_upload" + ) + + if uploaded_ca is not None: + if st.button("📤 Загрузить сводку СА", key="upload_ca_btn"): + with st.spinner("Загружаю файл..."): + try: + files = {"file": (uploaded_ca.name, uploaded_ca.read(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")} + response = requests.post(f"{API_BASE_URL}/svodka_ca/upload", files=files) + result = response.json() + + if response.status_code == 200: + st.success(f"✅ {result.get('message', 'Файл загружен')}") + st.info(f"ID объекта: {result.get('object_id', 'N/A')}") + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + except Exception as e: + st.error(f"❌ Ошибка: {str(e)}") + + # Вкладка 2: Сводки ПМ + with tab2: + st.header("📊 Сводки ПМ") + + col1, col2 = st.columns(2) + + with col1: + st.subheader("Данные по одному ОГ") + + og_id = st.selectbox( + "Выберите ОГ", + ["SNPZ", "KNPZ", "ANHK", "AchNPZ", "UNPZ", "UNH", "NOV", + "NovKuybNPZ", "KuybNPZ", "CyzNPZ", "TuapsNPZ", "RNPK", + "NVNPO", "KLNPZ", "PurNP", "YANOS"], + key="pm_single_og" + ) + + codes = st.multiselect( + "Выберите коды строк", + [78, 79, 394, 395, 396, 397, 81, 82, 83, 84], + default=[78, 79], + key="pm_single_codes" + ) + + columns = st.multiselect( + "Выберите столбцы", + ["ПП", "БП", "ТБ", "СЭБ", "НЭБ"], + default=["ПП", "СЭБ"], + key="pm_single_columns" + ) + + search = st.selectbox( + "Фильтр", + [None, "Итого"], + key="pm_single_search" + ) + + if st.button("🔍 Получить данные", key="pm_single_btn"): + if codes and columns: + with st.spinner("Получаю данные..."): + data = { + "id": og_id, + "codes": codes, + "columns": columns + } + if search: + data["search"] = search + + result, status = make_api_request("/svodka_pm/get_single_og", data) + + if status == 200: + st.success("✅ Данные получены") + st.json(result) + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + else: + st.warning("⚠️ Выберите коды и столбцы") + + with col2: + st.subheader("Данные по всем ОГ") + + codes_total = st.multiselect( + "Выберите коды строк", + [78, 79, 394, 395, 396, 397, 81, 82, 83, 84], + default=[78, 79], + key="pm_total_codes" + ) + + columns_total = st.multiselect( + "Выберите столбцы", + ["ПП", "БП", "ТБ", "СЭБ", "НЭБ"], + default=["ПП", "СЭБ"], + key="pm_total_columns" + ) + + search_total = st.selectbox( + "Фильтр", + [None, "Итого"], + key="pm_total_search" + ) + + if st.button("🔍 Получить данные по всем ОГ", key="pm_total_btn"): + if codes_total and columns_total: + with st.spinner("Получаю данные..."): + data = { + "codes": codes_total, + "columns": columns_total + } + if search_total: + data["search"] = search_total + + result, status = make_api_request("/svodka_pm/get_total_ogs", data) + + if status == 200: + st.success("✅ Данные получены") + st.json(result) + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + else: + st.warning("⚠️ Выберите коды и столбцы") + + # Вкладка 3: Сводки СА + with tab3: + st.header("🏭 Сводки СА") + + st.subheader("Получение данных из сводки СА") + + modes = st.multiselect( + "Выберите режимы", + ["plan", "fact", "normativ"], + default=["plan", "fact"], + key="ca_modes" + ) + + tables = st.multiselect( + "Выберите таблицы", + ["ТиП, %", "Топливо итого, тонн", "Топливо итого, %", + "Топливо на технологию, тонн", "Топливо на технологию, %", + "Топливо на энергетику, тонн", "Топливо на энергетику, %", + "Потери итого, тонн", "Потери итого, %"], + default=["ТиП, %", "Топливо итого, тонн"], + key="ca_tables" + ) + + if st.button("🔍 Получить данные СА", key="ca_btn"): + if modes and tables: + with st.spinner("Получаю данные..."): + data = { + "modes": modes, + "tables": tables + } + + result, status = make_api_request("/svodka_ca/get_data", data) + + if status == 200: + st.success("✅ Данные получены") + st.json(result) + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + else: + st.warning("⚠️ Выберите режимы и таблицы") + + # Вкладка 4: Мониторинг топлива + with tab4: + st.header("⛽ Мониторинг топлива") + + col1, col2 = st.columns(2) + + with col1: + st.subheader("Агрегация по колонкам") + + columns_fuel = st.multiselect( + "Выберите столбцы", + ["normativ", "total", "total_1"], + default=["normativ", "total"], + key="fuel_columns" + ) + + if st.button("🔍 Получить агрегированные данные", key="fuel_total_btn"): + if columns_fuel: + with st.spinner("Получаю данные..."): + data = { + "columns": columns_fuel + } + + result, status = make_api_request("/monitoring_fuel/get_total_by_columns", data) + + if status == 200: + st.success("✅ Данные получены") + st.json(result) + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + else: + st.warning("⚠️ Выберите столбцы") + + with col2: + st.subheader("Данные за месяц") + + month = st.selectbox( + "Выберите месяц", + [f"{i:02d}" for i in range(1, 13)], + key="fuel_month" + ) + + if st.button("🔍 Получить данные за месяц", key="fuel_month_btn"): + with st.spinner("Получаю данные..."): + data = { + "month": month + } + + result, status = make_api_request("/monitoring_fuel/get_month_by_code", data) + + if status == 200: + st.success("✅ Данные получены") + st.json(result) + else: + st.error(f"❌ Ошибка: {result.get('message', 'Неизвестная ошибка')}") + + # Футер + st.markdown("---") + st.markdown("### 📚 Документация API") + st.markdown(f"Полная документация доступна по адресу: {API_BASE_URL}/docs") + + # Информация о проекте + with st.expander("ℹ️ О проекте"): + st.markdown(""" + **NIN Excel Parsers API** - это веб-сервис для парсинга и обработки Excel-файлов нефтеперерабатывающих заводов. + + **Возможности:** + - 📊 Парсинг сводок ПМ (план и факт) + - 🏭 Парсинг сводок СА + - ⛽ Мониторинг топлива + + **Технологии:** + - FastAPI + - Pandas + - MinIO (S3-совместимое хранилище) + - Streamlit (веб-интерфейс) + """) + +if __name__ == "__main__": + main() \ No newline at end of file