Spaces:
Sleeping
Sleeping
Update services/report_data_handler.py
Browse files- services/report_data_handler.py +118 -1
services/report_data_handler.py
CHANGED
|
@@ -23,14 +23,24 @@ def fetch_latest_agentic_analysis(org_urn: str) -> Tuple[Optional[pd.DataFrame],
|
|
| 23 |
Returns the full dataframe and any error message, or None, None.
|
| 24 |
"""
|
| 25 |
logger.info(f"Starting fetch_latest_agentic_analysis for org_urn: {org_urn}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
if not org_urn:
|
| 27 |
logger.warning("fetch_latest_agentic_analysis: org_urn is missing.")
|
| 28 |
return None, "org_urn is missing."
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
try:
|
| 31 |
report_data_df, error = fetch_linkedin_posts_data_from_bubble(
|
| 32 |
data_type=BUBBLE_REPORT_TABLE_NAME,
|
| 33 |
-
|
|
|
|
|
|
|
| 34 |
)
|
| 35 |
|
| 36 |
if error:
|
|
@@ -336,3 +346,110 @@ def save_actionable_okrs(org_urn: str, actionable_okrs: Dict[str, Any], report_i
|
|
| 336 |
|
| 337 |
except Exception as e:
|
| 338 |
logger.exception(f"An unhandled exception occurred during the save_actionable_okrs orchestration for org_urn {org_urn}: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
Returns the full dataframe and any error message, or None, None.
|
| 24 |
"""
|
| 25 |
logger.info(f"Starting fetch_latest_agentic_analysis for org_urn: {org_urn}")
|
| 26 |
+
|
| 27 |
+
current_year = today.year
|
| 28 |
+
current_quarter = (today.month - 1) // 3 + 1
|
| 29 |
+
|
| 30 |
if not org_urn:
|
| 31 |
logger.warning("fetch_latest_agentic_analysis: org_urn is missing.")
|
| 32 |
return None, "org_urn is missing."
|
| 33 |
|
| 34 |
+
additional_constraint = [
|
| 35 |
+
{"key": 'quarter', "constraint_type": "equals", "value": current_quarter},
|
| 36 |
+
{"key": 'year', "constraint_type": "equals", "value": current_year}
|
| 37 |
+
]
|
| 38 |
try:
|
| 39 |
report_data_df, error = fetch_linkedin_posts_data_from_bubble(
|
| 40 |
data_type=BUBBLE_REPORT_TABLE_NAME,
|
| 41 |
+
constraint_value=org_urn,
|
| 42 |
+
constraint_key='organization_urn',
|
| 43 |
+
constraint_type = 'equals'
|
| 44 |
)
|
| 45 |
|
| 46 |
if error:
|
|
|
|
| 346 |
|
| 347 |
except Exception as e:
|
| 348 |
logger.exception(f"An unhandled exception occurred during the save_actionable_okrs orchestration for org_urn {org_urn}: {e}")
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
def fetch_and_reconstruct_data_from_bubble(report_df: pd.DataFrame) -> Optional[Dict[str, Any]]:
|
| 352 |
+
"""
|
| 353 |
+
Fetches the latest report, OKRs, Key Results, and Tasks from Bubble for a given organization
|
| 354 |
+
and reconstructs them into the nested structure expected by the application.
|
| 355 |
+
|
| 356 |
+
Args:
|
| 357 |
+
org_urn: The URN of the organization.
|
| 358 |
+
|
| 359 |
+
Returns:
|
| 360 |
+
A dictionary containing the reconstructed data ('report_str', 'actionable_okrs', etc.)
|
| 361 |
+
or None if the report is not found or an error occurs.
|
| 362 |
+
"""
|
| 363 |
+
# logger.info(f"Starting data fetch and reconstruction for org_urn: {org_urn}")
|
| 364 |
+
# try:
|
| 365 |
+
# # 1. Fetch the latest report for the organization
|
| 366 |
+
# # We add a sort field to get the most recent one.
|
| 367 |
+
# report_df, error = fetch_linkedin_posts_data_from_bubble(
|
| 368 |
+
# data_type=BUBBLE_REPORT_TABLE_NAME,
|
| 369 |
+
# org_urn=org_urn,
|
| 370 |
+
# constraint_key="organization_urn"
|
| 371 |
+
# )
|
| 372 |
+
|
| 373 |
+
# if error or report_df is None or report_df.empty:
|
| 374 |
+
# logger.error(f"Could not fetch latest report for org_urn {org_urn}. Error: {error}")
|
| 375 |
+
# return None
|
| 376 |
+
|
| 377 |
+
# Get the most recent report (assuming the first one is the latest)
|
| 378 |
+
latest_report = report_df.iloc[0]
|
| 379 |
+
report_id = latest_report.get('_id')
|
| 380 |
+
if not report_id:
|
| 381 |
+
logger.error("Fetched report is missing a Bubble '_id'.")
|
| 382 |
+
return None
|
| 383 |
+
|
| 384 |
+
logger.info(f"Fetched latest report with ID: {report_id}")
|
| 385 |
+
|
| 386 |
+
# 2. Fetch all related OKRs using the report_id
|
| 387 |
+
okrs_df, error = fetch_linkedin_posts_data_from_bubble(
|
| 388 |
+
data_type=BUBBLE_OKR_TABLE_NAME,
|
| 389 |
+
constraint_value=report_id,
|
| 390 |
+
constraint_key='report',
|
| 391 |
+
constraint_type = 'equals'
|
| 392 |
+
)
|
| 393 |
+
if error:
|
| 394 |
+
logger.error(f"Error fetching OKRs for report_id {report_id}: {error}")
|
| 395 |
+
okrs_df = pd.DataFrame()
|
| 396 |
+
|
| 397 |
+
# 3. Fetch all related Key Results using the OKR IDs
|
| 398 |
+
okr_ids = okrs_df['_id'].tolist() if not okrs_df.empty else []
|
| 399 |
+
krs_df = pd.DataFrame()
|
| 400 |
+
if okr_ids:
|
| 401 |
+
krs_df, error = fetch_linkedin_posts_data_from_bubble(
|
| 402 |
+
data_type=BUBBLE_KEY_RESULTS_TABLE_NAME,
|
| 403 |
+
constraint_value=okr_ids,
|
| 404 |
+
constraint_key='okr',
|
| 405 |
+
constraint_type='in'
|
| 406 |
+
)
|
| 407 |
+
if error:
|
| 408 |
+
logger.error(f"Error fetching Key Results for OKR IDs {okr_ids}: {error}")
|
| 409 |
+
krs_df = pd.DataFrame()
|
| 410 |
+
|
| 411 |
+
# 4. Fetch all related Tasks using the Key Result IDs
|
| 412 |
+
kr_ids = krs_df['_id'].tolist() if not krs_df.empty else []
|
| 413 |
+
tasks_df = pd.DataFrame()
|
| 414 |
+
if kr_ids:
|
| 415 |
+
tasks_df, error = fetch_linkedin_posts_data_from_bubble(
|
| 416 |
+
data_type=BUBBLE_TASKS_TABLE_NAME,
|
| 417 |
+
constraint_value=kr_ids,
|
| 418 |
+
constraint_key='key_result',
|
| 419 |
+
constraint_type='in'
|
| 420 |
+
)
|
| 421 |
+
if error:
|
| 422 |
+
logger.error(f"Error fetching Tasks for KR IDs {kr_ids}: {error}")
|
| 423 |
+
tasks_df = pd.DataFrame()
|
| 424 |
+
|
| 425 |
+
# 5. Reconstruct the nested 'actionable_okrs' dictionary
|
| 426 |
+
tasks_by_kr_id = tasks_df.groupby('key_result').apply(lambda x: x.to_dict('records')).to_dict()
|
| 427 |
+
krs_by_okr_id = krs_df.groupby('okr').apply(lambda x: x.to_dict('records')).to_dict()
|
| 428 |
+
|
| 429 |
+
reconstructed_okrs = []
|
| 430 |
+
for okr_data in okrs_df.to_dict('records'):
|
| 431 |
+
okr_id = okr_data['_id']
|
| 432 |
+
key_results_list = krs_by_okr_id.get(okr_id, [])
|
| 433 |
+
|
| 434 |
+
for kr_data in key_results_list:
|
| 435 |
+
kr_id = kr_data['_id']
|
| 436 |
+
# Attach tasks to each key result
|
| 437 |
+
kr_data['tasks'] = tasks_by_kr_id.get(kr_id, [])
|
| 438 |
+
|
| 439 |
+
# Attach key results to the objective
|
| 440 |
+
okr_data['key_results'] = key_results_list
|
| 441 |
+
reconstructed_okrs.append(okr_data)
|
| 442 |
+
|
| 443 |
+
actionable_okrs = {"okrs": reconstructed_okrs}
|
| 444 |
+
|
| 445 |
+
return {
|
| 446 |
+
"report_str": latest_report.get("report_text", "Nessun report trovato."),
|
| 447 |
+
"quarter": latest_report.get("quarter"),
|
| 448 |
+
"year": latest_report.get("year"),
|
| 449 |
+
"actionable_okrs": actionable_okrs,
|
| 450 |
+
"report_id": report_id
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
except Exception as e:
|
| 454 |
+
logger.exception(f"An unexpected error occurred during data reconstruction for org_urn {org_urn}: {e}")
|
| 455 |
+
return None
|