from google.cloud import bigquery from datetime import datetime, timezone PROJECT_ID = "propane-will-491900-m5" DATASET = "costguard_dataset" BILLING_TABLE = f"{PROJECT_ID}.{DATASET}.gcp_billing_export" def get_recommendations(budget_nok: float = 500.0) -> dict: client = bigquery.Client(project=PROJECT_ID) recommendations = [] # 1. Anomali: tjenester der siste 3d-snitt >= 2x 30d-snitt anomaly_query = f""" WITH base AS ( SELECT service.description AS service, AVG(cost) AS avg_30d FROM `{BILLING_TABLE}` WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY) GROUP BY service ), recent AS ( SELECT service.description AS service, AVG(cost) AS avg_3d FROM `{BILLING_TABLE}` WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY) GROUP BY service ) SELECT r.service, r.avg_3d, b.avg_30d, SAFE_DIVIDE(r.avg_3d, b.avg_30d) AS ratio FROM recent r JOIN base b ON r.service = b.service WHERE SAFE_DIVIDE(r.avg_3d, b.avg_30d) >= 2.0 AND b.avg_30d > 0.001 ORDER BY ratio DESC """ # 2. Sløsing: tjenester med kostnad men 0 aktivitet siste 7d waste_query = f""" WITH active AS ( SELECT DISTINCT service.description AS service FROM `{BILLING_TABLE}` WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AND cost > 0 ), all_svc AS ( SELECT DISTINCT service.description AS service FROM `{BILLING_TABLE}` WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY) AND cost > 0 ) SELECT a.service FROM all_svc a LEFT JOIN active b ON a.service = b.service WHERE b.service IS NULL """ try: # Anomalier for row in client.query(anomaly_query).result(): ratio = row.ratio or 0 severity = "high" if ratio >= 3 else "medium" savings = round(float(row.avg_3d - row.avg_30d) * 30 * 10, 2) # rough NOK recommendations.append({ "type": "anomaly", "severity": severity, "service": row.service, "message": f"Unormal kostnadsøkning på {row.service} — {ratio:.1f}x over normalt", "estimated_savings_nok": max(savings, 0) }) # Sløsing for row in client.query(waste_query).result(): recommendations.append({ "type": "waste", "severity": "low", "service": row.service, "message": f"{row.service} har hatt kostnad men ingen aktivitet siste 7 dager — vurder å skru av", "estimated_savings_nok": 0 }) except Exception as e: return {"recommendations": [], "total_estimated_savings_nok": 0, "error": str(e)} total_savings = sum(r["estimated_savings_nok"] for r in recommendations) return { "recommendations": recommendations, "total_estimated_savings_nok": round(total_savings, 2) }