integrate database writing procedures for logging purposes
This commit was merged in pull request #9.
This commit is contained in:
@@ -3,16 +3,19 @@ from __future__ import annotations
|
||||
import datetime
|
||||
import math
|
||||
from collections.abc import Mapping, Set
|
||||
from dataclasses import asdict
|
||||
from datetime import datetime as Datetime
|
||||
from typing import TYPE_CHECKING, Final, TypeAlias, cast
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import scipy.stats
|
||||
import sqlalchemy as sql
|
||||
from sklearn.metrics import mean_absolute_error, r2_score
|
||||
from sklearn.model_selection import KFold, RandomizedSearchCV
|
||||
from xgboost import XGBRegressor
|
||||
|
||||
from delta_barth import databases
|
||||
from delta_barth.analysis import parse
|
||||
from delta_barth.api.requests import (
|
||||
SalesPrognosisResponse,
|
||||
@@ -29,7 +32,8 @@ from delta_barth.constants import (
|
||||
SALES_MIN_NUM_DATAPOINTS,
|
||||
)
|
||||
from delta_barth.errors import STATUS_HANDLER, wrap_result
|
||||
from delta_barth.logging import logger_pipelines as logger
|
||||
from delta_barth.logging import logger_db, logger_pipelines
|
||||
from delta_barth.management import SESSION
|
||||
from delta_barth.types import (
|
||||
BestParametersXGBRegressor,
|
||||
DualDict,
|
||||
@@ -77,6 +81,21 @@ def _parse_df_to_results(
|
||||
return SalesPrognosisResults(daten=tuple(df_formatted)) # type: ignore
|
||||
|
||||
|
||||
def _write_sales_forecast_stats(
|
||||
stats: SalesForecastStatistics,
|
||||
) -> None:
|
||||
stats_db = asdict(stats)
|
||||
_ = stats_db.pop("xgb_params")
|
||||
xgb_params = stats.xgb_params
|
||||
|
||||
with SESSION.db_engine.begin() as conn:
|
||||
res = conn.execute(sql.insert(databases.sf_stats).values(stats_db))
|
||||
sf_id = cast(int, res.inserted_primary_key[0]) # type: ignore
|
||||
if xgb_params is not None:
|
||||
xgb_params["forecast_id"] = sf_id
|
||||
conn.execute(sql.insert(databases.sf_XGB).values(xgb_params))
|
||||
|
||||
|
||||
@wrap_result()
|
||||
def _parse_api_resp_to_df_wrapped(
|
||||
resp: SalesPrognosisResponse,
|
||||
@@ -91,23 +110,11 @@ def _parse_df_to_results_wrapped(
|
||||
return _parse_df_to_results(data)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Input:
|
||||
# DataFrame df mit Columns f_umsatz_fakt, firmen, art, v_warengrp
|
||||
# kunde (muss enthalten sein in df['firmen']['firma_refid'])
|
||||
|
||||
# Output:
|
||||
# Integer umsetzung (Prognose möglich): 0 ja, 1 nein (zu wenig Daten verfügbar),
|
||||
# 2 nein (Daten nicht für Prognose geeignet)
|
||||
# DataFrame test: Jahr, Monat, Vorhersage
|
||||
# -------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Prognose Umsatz je Firma
|
||||
|
||||
|
||||
# TODO: check usage of separate exception and handle it in API function
|
||||
# TODO set min number of data points as constant, not parameter
|
||||
@wrap_result()
|
||||
def _write_sales_forecast_stats_wrapped(
|
||||
stats: SalesForecastStatistics,
|
||||
) -> None:
|
||||
return _write_sales_forecast_stats(stats)
|
||||
|
||||
|
||||
def _preprocess_sales(
|
||||
@@ -341,7 +348,7 @@ def _export_on_fail(
|
||||
return SalesPrognosisResultsExport(response=response, status=status)
|
||||
|
||||
|
||||
def pipeline_sales(
|
||||
def pipeline_sales_forecast(
|
||||
session: Session,
|
||||
company_id: int | None = None,
|
||||
start_date: Datetime | None = None,
|
||||
@@ -352,8 +359,8 @@ def pipeline_sales(
|
||||
start_date=start_date,
|
||||
)
|
||||
if status != STATUS_HANDLER.SUCCESS:
|
||||
logger.error(
|
||||
"Error during sales prognosis data retrieval, Status: %s",
|
||||
logger_pipelines.error(
|
||||
"Error during sales forecast data retrieval, Status: %s",
|
||||
status,
|
||||
stack_info=True,
|
||||
)
|
||||
@@ -365,8 +372,8 @@ def pipeline_sales(
|
||||
target_features=FEATURES_SALES_PROGNOSIS,
|
||||
)
|
||||
if pipe.status != STATUS_HANDLER.SUCCESS:
|
||||
logger.error(
|
||||
"Error during sales prognosis preprocessing, Status: %s",
|
||||
logger_pipelines.error(
|
||||
"Error during sales forecast preprocessing, Status: %s",
|
||||
pipe.status,
|
||||
stack_info=True,
|
||||
)
|
||||
@@ -377,9 +384,16 @@ def pipeline_sales(
|
||||
min_num_data_points=SALES_MIN_NUM_DATAPOINTS,
|
||||
base_num_data_points_months=SALES_BASE_NUM_DATAPOINTS_MONTHS,
|
||||
)
|
||||
if pipe.statistics is not None:
|
||||
res = _write_sales_forecast_stats_wrapped(pipe.statistics)
|
||||
if res.status != STATUS_HANDLER.SUCCESS:
|
||||
logger_db.error(
|
||||
"[DB] Error during write process of sales forecast statistics: %s",
|
||||
res.status,
|
||||
)
|
||||
if pipe.status != STATUS_HANDLER.SUCCESS:
|
||||
logger.error(
|
||||
"Error during sales prognosis main processing, Status: %s",
|
||||
logger_pipelines.error(
|
||||
"Error during sales forecast main processing, Status: %s",
|
||||
pipe.status,
|
||||
stack_info=True,
|
||||
)
|
||||
@@ -390,8 +404,8 @@ def pipeline_sales(
|
||||
feature_map=DualDict(),
|
||||
)
|
||||
if pipe.status != STATUS_HANDLER.SUCCESS:
|
||||
logger.error(
|
||||
"Error during sales prognosis postprocessing, Status: %s",
|
||||
logger_pipelines.error(
|
||||
"Error during sales forecast postprocessing, Status: %s",
|
||||
pipe.status,
|
||||
stack_info=True,
|
||||
)
|
||||
|
||||
@@ -34,8 +34,10 @@ logger_session = logging.getLogger("delta_barth.session")
|
||||
logger_session.setLevel(logging.DEBUG)
|
||||
logger_wrapped_results = logging.getLogger("delta_barth.wrapped_results")
|
||||
logger_wrapped_results.setLevel(logging.DEBUG)
|
||||
logger_pipelines = logging.getLogger("delta_barth.logger_pipelines")
|
||||
logger_pipelines = logging.getLogger("delta_barth.pipelines")
|
||||
logger_pipelines.setLevel(logging.DEBUG)
|
||||
logger_db = logging.getLogger("delta_barth.databases")
|
||||
logger_db.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def setup_logging(
|
||||
|
||||
@@ -11,7 +11,9 @@ def pipeline_sales_forecast(
|
||||
company_id: int | None,
|
||||
start_date: Datetime | None,
|
||||
) -> JsonExportResponse:
|
||||
result = forecast.pipeline_sales(SESSION, company_id=company_id, start_date=start_date)
|
||||
result = forecast.pipeline_sales_forecast(
|
||||
SESSION, company_id=company_id, start_date=start_date
|
||||
)
|
||||
export = JsonExportResponse(result.model_dump_json())
|
||||
|
||||
return export
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
import pprint
|
||||
import typing as t
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass, field
|
||||
@@ -29,6 +30,10 @@ class Status(BaseModel):
|
||||
message: SkipValidation[str] = ""
|
||||
api_server_error: SkipValidation[DelBarApiError | None] = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
py_repr = self.model_dump()
|
||||
return pprint.pformat(py_repr, indent=4, sort_dicts=False)
|
||||
|
||||
|
||||
class ResponseType(BaseModel):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user