streamlit fix

This commit is contained in:
2025-09-01 18:57:39 +03:00
parent 456e9935f0
commit 47a7344755
39 changed files with 491 additions and 555 deletions

View File

@@ -0,0 +1,396 @@
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://fastapi: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()