streamlit fix
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
[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
|
||||
@@ -1 +0,0 @@
|
||||
web: python /app/run_stand.py
|
||||
@@ -1,66 +0,0 @@
|
||||
# 🚀 Быстрый старт 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
|
||||
```
|
||||
@@ -1,197 +0,0 @@
|
||||
# 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=.
|
||||
```
|
||||
|
||||
## 📝 Лицензия
|
||||
|
||||
Проект разработан для внутреннего использования НИН.
|
||||
@@ -1,186 +0,0 @@
|
||||
# 🚀 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
|
||||
@@ -1,185 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,32 +0,0 @@
|
||||
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
|
||||
command: server /data --console-address ":9001"
|
||||
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:
|
||||
@@ -1,17 +0,0 @@
|
||||
applications:
|
||||
- name: nin-python-parser-dev-test
|
||||
buildpack: python_buildpack
|
||||
health-check-type: web
|
||||
services:
|
||||
- logging-shared-dev
|
||||
command: python /app/run_stand.py
|
||||
path: .
|
||||
disk_quota: 2G
|
||||
memory: 4G
|
||||
instances: 1
|
||||
env:
|
||||
MINIO_ENDPOINT: s3-region1.ppc-jv-dev.sibintek.ru
|
||||
MINIO_ACCESS_KEY: 00a70fac02c1208446de
|
||||
MINIO_SECRET_KEY: 1gk9tVYEEoH9ADRxb4kiAuCo6CCISdV6ie0p6oDO
|
||||
MINIO_BUCKET: bucket-476684e7-1223-45ac-a101-8b5aeda487d6
|
||||
MINIO_SECURE: false
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
{"version":"1","format":"xl-single","id":"29118f57-702e-4363-9a41-9f06655e449d","xl":{"version":"3","this":"195a90f4-fc26-46a8-b6d4-0b50b99b1342","sets":[["195a90f4-fc26-46a8-b6d4-0b50b99b1342"]],"distributionAlgo":"SIPMOD+PARITY"}}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -11,5 +11,4 @@ requests>=2.31.0
|
||||
# pytest-cov>=4.0.0
|
||||
# pytest-mock>=3.10.0
|
||||
httpx>=0.24.0
|
||||
numpy
|
||||
streamlit>=1.28.0
|
||||
numpy
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1 +0,0 @@
|
||||
python-3.11.*
|
||||
@@ -1,396 +0,0 @@
|
||||
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 = st.tabs([
|
||||
"📊 Сводки ПМ",
|
||||
"🏭 Сводки СА",
|
||||
"⛽ Мониторинг топлива"
|
||||
])
|
||||
|
||||
# Вкладка 1: Сводки ПМ - полный функционал
|
||||
with tab1:
|
||||
st.header("📊 Сводки ПМ - Полный функционал")
|
||||
|
||||
# Секция загрузки файлов
|
||||
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', 'Неизвестная ошибка')}")
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# Секция получения данных
|
||||
st.subheader("🔍 Получение данных")
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
if st.button("🔍 Получить данные по ОГ", key="pm_single_btn"):
|
||||
if codes and columns:
|
||||
with st.spinner("Получаю данные..."):
|
||||
data = {
|
||||
"id": og_id,
|
||||
"codes": codes,
|
||||
"columns": columns
|
||||
}
|
||||
|
||||
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, 394, 395],
|
||||
key="pm_total_codes"
|
||||
)
|
||||
|
||||
columns_total = st.multiselect(
|
||||
"Выберите столбцы",
|
||||
["БП", "ПП", "СЭБ", "Факт", "План"],
|
||||
default=["БП", "ПП", "СЭБ"],
|
||||
key="pm_total_columns"
|
||||
)
|
||||
|
||||
if st.button("🔍 Получить данные по всем ОГ", key="pm_total_btn"):
|
||||
if codes_total and columns_total:
|
||||
with st.spinner("Получаю данные..."):
|
||||
data = {
|
||||
"codes": codes_total,
|
||||
"columns": columns_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("⚠️ Выберите коды и столбцы")
|
||||
|
||||
# Вкладка 2: Сводки СА - полный функционал
|
||||
with tab2:
|
||||
st.header("🏭 Сводки СА - Полный функционал")
|
||||
|
||||
# Секция загрузки файлов
|
||||
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)}")
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# Секция получения данных
|
||||
st.subheader("🔍 Получение данных")
|
||||
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
st.subheader("Параметры запроса")
|
||||
|
||||
modes = st.multiselect(
|
||||
"Выберите режимы",
|
||||
["plan", "fact", "normativ"],
|
||||
default=["plan", "fact"],
|
||||
key="ca_modes"
|
||||
)
|
||||
|
||||
tables = st.multiselect(
|
||||
"Выберите таблицы",
|
||||
["ТиП", "Топливо", "Потери"],
|
||||
default=["ТиП", "Топливо"],
|
||||
key="ca_tables"
|
||||
)
|
||||
|
||||
with col2:
|
||||
st.subheader("Результат")
|
||||
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("⚠️ Выберите режимы и таблицы")
|
||||
|
||||
# Вкладка 3: Мониторинг топлива - полный функционал
|
||||
with tab3:
|
||||
st.header("⛽ Мониторинг топлива - Полный функционал")
|
||||
|
||||
# Секция загрузки файлов
|
||||
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.markdown("---")
|
||||
|
||||
# Секция получения данных
|
||||
st.subheader("🔍 Получение данных")
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user