Обновил дев докер компоуз, работает сводка СА (но там пустые данные)

This commit is contained in:
2025-09-02 11:28:07 +03:00
parent 8ed61a3c0b
commit e3077252a8
11 changed files with 124 additions and 25 deletions

1
.gitignore vendored
View File

@@ -16,6 +16,7 @@ python_parser/app/schemas/test_schemas/test_adapters/__pycache__/
python_parser/app/schemas/test_schemas/test_app/__pycache__/ python_parser/app/schemas/test_schemas/test_app/__pycache__/
nin_python_parser nin_python_parser
*.pyc
*.py[cod] *.py[cod]
*$py.class *$py.class

View File

@@ -14,7 +14,7 @@ services:
restart: unless-stopped restart: unless-stopped
fastapi: fastapi:
build: ./python_parser image: python:3.11-slim
container_name: svodka_fastapi_dev container_name: svodka_fastapi_dev
ports: ports:
- "8000:8000" - "8000:8000"
@@ -24,9 +24,20 @@ services:
- MINIO_SECRET_KEY=minioadmin - MINIO_SECRET_KEY=minioadmin
- MINIO_SECURE=false - MINIO_SECURE=false
- MINIO_BUCKET=svodka-data - MINIO_BUCKET=svodka-data
volumes:
# Монтируем исходный код для автоматической перезагрузки
- ./python_parser:/app
# Монтируем requirements.txt для установки зависимостей
- ./python_parser/requirements.txt:/app/requirements.txt
working_dir: /app
depends_on: depends_on:
- minio - minio
restart: unless-stopped restart: unless-stopped
command: >
bash -c "
pip install --no-cache-dir -r requirements.txt &&
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
"
streamlit: streamlit:
image: python:3.11-slim image: python:3.11-slim

View File

@@ -17,7 +17,7 @@ class SvodkaCAParser(ParserPort):
# Используем схемы Pydantic как единый источник правды # Используем схемы Pydantic как единый источник правды
register_getter_from_schema( register_getter_from_schema(
parser_instance=self, parser_instance=self,
getter_name="get_data", getter_name="get_ca_data",
method=self._get_data_wrapper, method=self._get_data_wrapper,
schema_class=SvodkaCARequest, schema_class=SvodkaCARequest,
description="Получение данных по режимам и таблицам" description="Получение данных по режимам и таблицам"
@@ -31,16 +31,74 @@ class SvodkaCAParser(ParserPort):
modes = validated_params["modes"] modes = validated_params["modes"]
tables = validated_params["tables"] tables = validated_params["tables"]
# TODO: Переделать под новую архитектуру # Проверяем, есть ли данные в data_dict (из парсинга) или в df (из загрузки)
data_dict = {} if hasattr(self, 'data_dict') and self.data_dict is not None:
# Данные из парсинга
data_source = self.data_dict
elif hasattr(self, 'df') and self.df is not None and not self.df.empty:
# Данные из загрузки - преобразуем DataFrame обратно в словарь
data_source = self._df_to_data_dict()
else:
return {}
# Фильтруем данные по запрошенным режимам и таблицам
result_data = {}
for mode in modes: for mode in modes:
data_dict[mode] = self.get_data(self.df, mode, tables) if mode in data_source:
return self.data_dict_to_json(data_dict) result_data[mode] = {}
for table_name, table_data in data_source[mode].items():
if table_name in tables:
result_data[mode][table_name] = table_data
return result_data
def _df_to_data_dict(self):
"""Преобразование DataFrame обратно в словарь данных"""
if not hasattr(self, 'df') or self.df is None or self.df.empty:
return {}
data_dict = {}
# Группируем данные по режимам и таблицам
for _, row in self.df.iterrows():
mode = row.get('mode')
table = row.get('table')
data = row.get('data')
if mode and table and data is not None:
if mode not in data_dict:
data_dict[mode] = {}
data_dict[mode][table] = data
return data_dict
def parse(self, file_path: str, params: dict) -> pd.DataFrame: def parse(self, file_path: str, params: dict) -> pd.DataFrame:
"""Парсинг файла и возврат DataFrame""" """Парсинг файла и возврат DataFrame"""
# Сохраняем DataFrame для использования в геттерах # Парсим данные и сохраняем словарь для использования в геттерах
self.df = self.parse_svodka_ca(file_path, params) self.data_dict = self.parse_svodka_ca(file_path, params)
# Преобразуем словарь в DataFrame для совместимости с services.py
# Создаем простой DataFrame с информацией о загруженных данных
if self.data_dict:
# Создаем DataFrame с информацией о режимах и таблицах
data_rows = []
for mode, tables in self.data_dict.items():
for table_name, table_data in tables.items():
if table_data:
data_rows.append({
'mode': mode,
'table': table_name,
'rows_count': len(table_data),
'data': table_data
})
if data_rows:
df = pd.DataFrame(data_rows)
self.df = df
return df
# Если данных нет, возвращаем пустой DataFrame
self.df = pd.DataFrame()
return self.df return self.df
def parse_svodka_ca(self, file_path: str, params: dict) -> dict: def parse_svodka_ca(self, file_path: str, params: dict) -> dict:
@@ -147,12 +205,22 @@ class SvodkaCAParser(ParserPort):
# Сортируем по индексу (id) и по столбцу 'table' # Сортируем по индексу (id) и по столбцу 'table'
combined_df = combined_df.sort_values(by=['id', 'table'], axis=0) combined_df = combined_df.sort_values(by=['id', 'table'], axis=0)
# Устанавливаем id как индекс # Преобразуем DataFrame в словарь по режимам и таблицам
# combined_df.set_index('id', inplace=True) # Для сводки СА у нас есть только один режим - 'fact' (по умолчанию)
# Но нужно определить режим из данных или параметров
mode = params.get('mode', 'fact') # По умолчанию 'fact'
return combined_df data_dict = {mode: {}}
# Группируем данные по таблицам
for table_name, group_df in combined_df.groupby('table'):
# Удаляем колонку 'table' из результата
table_data = group_df.drop('table', axis=1)
data_dict[mode][table_name] = table_data.to_dict('records')
return data_dict
else: else:
return None return {}
def extract_all_tables(self, file_path, sheet_name=0): def extract_all_tables(self, file_path, sheet_name=0):
"""Извлечение всех таблиц из Excel файла""" """Извлечение всех таблиц из Excel файла"""

View File

@@ -106,7 +106,26 @@ class ReportService:
# Получаем параметры запроса # Получаем параметры запроса
get_params = request.get_params or {} get_params = request.get_params or {}
# Определяем имя геттера из параметра mode # Для svodka_ca определяем режим из данных или используем 'fact' по умолчанию
if request.report_type == 'svodka_ca':
# Извлекаем режим из DataFrame или используем 'fact' по умолчанию
if hasattr(parser, 'df') and parser.df is not None and not parser.df.empty:
modes_in_df = parser.df['mode'].unique() if 'mode' in parser.df.columns else ['fact']
# Используем первый найденный режим или 'fact' по умолчанию
default_mode = modes_in_df[0] if len(modes_in_df) > 0 else 'fact'
else:
default_mode = 'fact'
# Устанавливаем режим в параметры, если он не указан
if 'mode' not in get_params:
get_params['mode'] = default_mode
# Определяем имя геттера
if request.report_type == 'svodka_ca':
# Для svodka_ca используем геттер get_ca_data
getter_name = 'get_ca_data'
else:
# Для других парсеров определяем из параметра mode
getter_name = get_params.pop("mode", None) getter_name = get_params.pop("mode", None)
if not getter_name: if not getter_name:
# Если режим не указан, берем первый доступный # Если режим не указан, берем первый доступный