87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
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)
|
|
}
|