Spaces:
Running
Running
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
|