From 1bfe3c0cd8c05507315012540e3df55991f7596d Mon Sep 17 00:00:00 2001 From: Maksim Date: Thu, 4 Sep 2025 22:53:01 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5?= =?UTF-8?q?=D1=82!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- streamlit_app/async_upload_page.py | 36 ++++++++++++++------- streamlit_app/tasks_page.py | 51 +++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/streamlit_app/async_upload_page.py b/streamlit_app/async_upload_page.py index dfa967c..d5adadb 100644 --- a/streamlit_app/async_upload_page.py +++ b/streamlit_app/async_upload_page.py @@ -5,43 +5,57 @@ import streamlit as st import asyncio import threading import time +import json +import os from api_client import upload_file_to_api from config import PARSER_TABS +# Глобальное хранилище задач (в реальном приложении лучше использовать Redis или БД) +TASKS_STORAGE = {} + def upload_file_async_background(endpoint, file_data, filename, task_id): """Асинхронная загрузка файла в фоновом режиме""" + global TASKS_STORAGE + try: + # Обновляем статус на "running" + TASKS_STORAGE[task_id] = { + 'status': 'running', + 'filename': filename, + 'endpoint': endpoint, + 'started_at': time.time(), + 'progress': 0 + } + # Имитируем асинхронную работу time.sleep(1) # Небольшая задержка для демонстрации # Выполняем загрузку result, status = upload_file_to_api(endpoint, file_data, filename) - # Сохраняем результат в session_state - if 'upload_tasks' not in st.session_state: - st.session_state.upload_tasks = {} - - st.session_state.upload_tasks[task_id] = { + # Сохраняем результат в глобальном хранилище + TASKS_STORAGE[task_id] = { 'status': 'completed' if status == 200 else 'failed', 'result': result, 'status_code': status, 'filename': filename, 'endpoint': endpoint, - 'completed_at': time.time() + 'started_at': TASKS_STORAGE.get(task_id, {}).get('started_at', time.time()), + 'completed_at': time.time(), + 'progress': 100 } except Exception as e: # Сохраняем ошибку - if 'upload_tasks' not in st.session_state: - st.session_state.upload_tasks = {} - - st.session_state.upload_tasks[task_id] = { + TASKS_STORAGE[task_id] = { 'status': 'failed', 'error': str(e), 'filename': filename, 'endpoint': endpoint, - 'completed_at': time.time() + 'started_at': TASKS_STORAGE.get(task_id, {}).get('started_at', time.time()), + 'completed_at': time.time(), + 'progress': 0 } diff --git a/streamlit_app/tasks_page.py b/streamlit_app/tasks_page.py index 512655a..440ce9c 100644 --- a/streamlit_app/tasks_page.py +++ b/streamlit_app/tasks_page.py @@ -4,6 +4,7 @@ import streamlit as st from datetime import datetime import time +from async_upload_page import TASKS_STORAGE def render_tasks_page(): @@ -20,7 +21,17 @@ def render_tasks_page(): with col2: if st.button("🗑️ Очистить завершенные", key="clear_completed_btn", use_container_width=True): - st.info("Функция очистки будет добавлена в следующих версиях") + # Удаляем завершенные и неудачные задачи + tasks_to_remove = [] + for task_id, task in TASKS_STORAGE.items(): + if task.get('status') in ['completed', 'failed']: + tasks_to_remove.append(task_id) + + for task_id in tasks_to_remove: + del TASKS_STORAGE[task_id] + + st.success(f"✅ Удалено {len(tasks_to_remove)} завершенных задач") + st.rerun() with col3: auto_refresh = st.checkbox("🔄 Автообновление", key="auto_refresh_checkbox") @@ -36,8 +47,8 @@ def render_tasks_page(): # Статистика задач st.subheader("📊 Статистика задач") - # Получаем задачи из session_state - tasks = st.session_state.get('upload_tasks', {}) + # Получаем задачи из глобального хранилища + tasks = TASKS_STORAGE # Подсчитываем статистику total_tasks = len(tasks) @@ -68,8 +79,8 @@ def render_tasks_page(): # Список задач st.subheader("📋 Список задач") - # Получаем задачи из session_state - tasks = st.session_state.get('upload_tasks', {}) + # Получаем задачи из глобального хранилища + tasks = TASKS_STORAGE if tasks: # Показываем задачи @@ -90,9 +101,25 @@ def render_tasks_page(): st.write(f"**Файл:** {task.get('filename', 'Unknown')}") st.write(f"**Эндпоинт:** {task.get('endpoint', 'Unknown')}") + # Показываем прогресс для выполняющихся задач + if task.get('status') == 'running': + progress = task.get('progress', 0) + st.write(f"**Прогресс:** {progress}%") + st.progress(progress / 100) + + # Показываем время выполнения + if task.get('started_at'): + started_time = datetime.fromtimestamp(task['started_at']).strftime("%Y-%m-%d %H:%M:%S") + st.write(f"**Начата:** {started_time}") + if task.get('completed_at'): completed_time = datetime.fromtimestamp(task['completed_at']).strftime("%Y-%m-%d %H:%M:%S") st.write(f"**Завершена:** {completed_time}") + + # Показываем длительность + if task.get('started_at'): + duration = task['completed_at'] - task['started_at'] + st.write(f"**Длительность:** {duration:.1f} сек") if task.get('result'): result = task['result'] @@ -112,9 +139,9 @@ def render_tasks_page(): st.info("Функция отмены будет реализована в следующих версиях") else: if st.button("🗑️ Удалить", key=f"delete_{task_id}_btn", use_container_width=True): - # Удаляем задачу из session_state - if 'upload_tasks' in st.session_state: - del st.session_state.upload_tasks[task_id] + # Удаляем задачу из глобального хранилища + if task_id in TASKS_STORAGE: + del TASKS_STORAGE[task_id] st.rerun() else: # Пустое состояние @@ -128,15 +155,15 @@ def render_tasks_page(): # Кнопка для создания тестовой задачи if st.button("🧪 Создать тестовую задачу", key="create_test_task_btn"): test_task_id = f"test_task_{int(time.time())}" - if 'upload_tasks' not in st.session_state: - st.session_state.upload_tasks = {} - st.session_state.upload_tasks[test_task_id] = { + TASKS_STORAGE[test_task_id] = { 'status': 'completed', 'filename': 'test_file.zip', 'endpoint': '/test/upload', 'result': {'message': 'Тестовая задача выполнена', 'object_id': 'test-123'}, - 'completed_at': time.time() + 'started_at': time.time() - 5, # 5 секунд назад + 'completed_at': time.time(), + 'progress': 100 } st.rerun()