File size: 4,104 Bytes
e972379
 
 
 
 
 
 
 
 
 
 
dc8d64e
e972379
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
library(plumber)
library(dplyr)
library(DBI)
library(RPostgres)
library(httr2)
library(jsonlite)

source("00_db_helper.R")
# source("backend/00_db_helper.R")

# Baca statistik training sekali saja saat API start
# train_stats <- NULL
if (file.exists("models/train_statistics.rds")) {
  train_stats <- readRDS("models/train_statistics.rds")
  # print(train_stats)
} else {
  con <- connect_supabase()
  train_stats <- dbGetQuery(con, "SELECT * FROM mlops.train_statistics ORDER BY create_date DESC LIMIT 1")
  DBI::dbDisconnect(con)
}

#* @filter cors
function(req, res) {
  res$setHeader("Access-Control-Allow-Origin", "*")
  res$setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
  res$setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization")

  if (req$REQUEST_METHOD == "OPTIONS") {
    res$status <- 200
    return(list())
  }
  plumber::forward()
}

#* Mengambil ringkasan performa model
#* @param window:int Ukuran window data
#* @get /performance
function(window = 100) {
  con <- connect_supabase()
  db_res <- dbGetQuery(con,  
    "SELECT predicted_value FROM mlops.predictions ORDER BY timestamp DESC LIMIT $1", 
    list(as.integer(window))
  )
  
  total_db_res <- dbGetQuery(con, "SELECT count(predicted_value) as total FROM mlops.predictions")
  dbDisconnect(con)
  
  if(nrow(db_res) == 0) {
    return(list(total = 0, mean_pred = NA, sd_pred = NA))
  }
  
  list(
    total = total_db_res$total,
    window = window, 
    mean_pred = mean(db_res$predicted_value, na.rm = TRUE),
    sd_pred = sd(db_res$predicted_value, na.rm = TRUE),
    min_pred = min(db_res$predicted_value, na.rm = TRUE),
    max_pred = max(db_res$predicted_value, na.rm = TRUE)
  )
}

#* Mengambil data logs dan drift yang sudah diproses
#* @param window:int Ukuran window data
#* @param drift_feature:str Fitur yang ingin dihitung Z-Score nya
#* @get /logs-drift
function(window = 100) {
  con <- connect_supabase()
  query_sql <- "

  WITH exploded_data AS (

    SELECT 

      request_id,

      timestamp,

      variant, version, row_id, 

      predicted_value,

      (input_features->>'displ')::numeric AS displ,

      (input_features->>'year')::numeric AS year,

      (input_features->>'cyl')::numeric AS cyl,

      (input_features->>'class')::text as class, 

      status, 

      COALESCE(error_message::text, '') AS error_message

    FROM mlops.predictions

    WHERE status = 'SUCCESS'

    ORDER BY timestamp DESC

    LIMIT %d

  )

  SELECT 

    *,

    ABS(displ - %f) / %f AS z_displ,

    ABS(year - %f) / %f AS z_year,

    ABS(cyl - %f) / %f AS z_cyl

  FROM exploded_data;

  "
  # print(train_stats)
  query_filled <- sprintf(
    query_sql,
    as.integer(window),
    train_stats$displ_mean, train_stats$displ_sd,
    train_stats$year_mean, train_stats$year_sd,
    train_stats$cyl_mean, train_stats$cyl_sd
  )
  # print(query_filled)

  final_data <- dbGetQuery(con, query_filled)
  # print("final_data:")
  # print(head(final_data))
  # print(str(final_data))
  
  # Jika query kosong, langsung kembalikan data frame kosong
  if(nrow(final_data) == 0) {
    dbDisconnect(con)
    return(list(data = data.frame()))
  }

  actuals_db <- tryCatch({
    dbGetQuery(con, "SELECT request_id, row_id, actual_value FROM mlops.actuals;")
  }, error = function(e) { 
    data.frame(request_id = character(), row_id = character(), actual_value = numeric()) 
  })
  dbDisconnect(con)
  
  
  # Gabung Actual
  # print(nrow(actuals_db) > 0) 
  # print("row_id" %in% names(final_data))
  if (nrow(actuals_db) > 0 && "row_id" %in% names(final_data)) {
    actuals_db$request_id <- as.character(actuals_db$request_id)
    actuals_db$row_id <- as.character(actuals_db$row_id)
    final_data <- final_data %>% 
      left_join(actuals_db, by = c("request_id", "row_id"))
    # print(final_data)
  } else {
    final_data$actual_value <- NA_real_
  }
  # print("final_data:")
  # print(nrow(final_data))
  # print(str(final_data))
    
  return(final_data)
}