geo/backend/app/services/attribution/roi_calculator.py

60 lines
2.0 KiB
Python

from app.models.attribution_record import AttributionRecord
class ROICalculator:
INDUSTRY_AVG_CITATION_VALUE = 50.0
def calculate_roi(
self,
subscription_cost: float,
score_delta: float,
attribution_records: list[AttributionRecord],
) -> dict:
value_generated = score_delta * self.INDUSTRY_AVG_CITATION_VALUE
if subscription_cost > 0:
roi_percentage = round(
(value_generated - subscription_cost) / subscription_cost * 100, 2
)
else:
roi_percentage = 0.0
break_even_delta = self.estimate_break_even(subscription_cost)
return {
"roi_percentage": roi_percentage,
"value_generated": round(value_generated, 2),
"cost": subscription_cost,
"break_even_delta": round(break_even_delta, 2),
}
def generate_ab_comparison(
self,
before_score: float,
after_score: float,
before_dimensions: dict,
after_dimensions: dict,
) -> dict:
overall_delta = round(after_score - before_score, 2)
dimensions = []
all_names = set(list(before_dimensions.keys()) + list(after_dimensions.keys()))
for name in all_names:
b = before_dimensions.get(name, {}).get("score", 0)
a = after_dimensions.get(name, {}).get("score", 0)
delta = round(a - b, 2)
dimensions.append({
"name": name,
"before": b,
"after": a,
"delta": delta,
"improved": delta > 0,
})
return {
"overall_before": before_score,
"overall_after": after_score,
"overall_delta": overall_delta,
"dimensions": dimensions,
}
def estimate_break_even(self, subscription_cost: float) -> float:
if self.INDUSTRY_AVG_CITATION_VALUE == 0:
return 0.0
return subscription_cost / self.INDUSTRY_AVG_CITATION_VALUE