|
from fastapi import FastAPI |
|
|
|
import re |
|
import inspect |
|
import numpy as np |
|
import pandas as pd |
|
import os |
|
|
|
from datetime import datetime |
|
|
|
from sentence_transformers import SentenceTransformer |
|
from sentence_transformers.util import cos_sim |
|
from sentence_transformers import CrossEncoder |
|
|
|
|
|
import psycopg2 |
|
|
|
db_user = os.environ["DB_NAME"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mydb = psycopg2.connect( |
|
host=os.environ["DB_HOST"], |
|
user=os.environ["DB_USER"], |
|
port=os.environ["DB_PORT"], |
|
database=os.environ["DB_NAME"], |
|
password=os.environ["DB_PASSWORD"] |
|
) |
|
|
|
|
|
|
|
|
|
|
|
df_sample = pd.read_sql(f"SELECT * FROM sample", mydb) |
|
df_bobot = pd.read_sql(f"SELECT * FROM bobot", mydb) |
|
|
|
df_sample["tg_bayar"] = pd.to_datetime(df_sample['tg_bayar']).dt.date |
|
df_sample["tg_akhir_pkb"] = pd.to_datetime(df_sample['tg_akhir_pkb']).dt.date |
|
df_sample["tg_akhir_stnk"] = pd.to_datetime(df_sample['tg_akhir_stnk']).dt.date |
|
|
|
|
|
df_bobot['BOBOT'] = [float(x.replace(",",".")) for x in df_bobot['BOBOT']] |
|
df_bobot["JENIS_KENDARAAN"] = [x[:-2] + x[-1] if x[-2] == "." else x for x in df_bobot["JENIS_KENDARAAN"]] |
|
|
|
dict_swdkllj = { |
|
"A":3000, |
|
"B":23000, |
|
"C1":35000, |
|
"C2":83000, |
|
"DP":35000, |
|
"DU":73000, |
|
"EP":153000, |
|
"EU":90000, |
|
"F":163000 |
|
} |
|
|
|
def find_swdkllj(row): |
|
cc = int(row["jumlah_cc"]) |
|
nm = str(row["nm_jenis_kb"]).upper() |
|
|
|
if nm in ["AMBULANCE", "DAMKAR", "MOBIL JENAZAH"]: |
|
return "A" |
|
if nm in ["ALAT BERAT"]: |
|
return "B" |
|
if nm in ["SEDAN", "JEEP", "MINIBUS"]: |
|
return "DP" |
|
|
|
if "SPD. MOTOR" in nm: |
|
if cc <= 50: |
|
return "A" |
|
elif cc <= 250: |
|
return "C1" |
|
else: |
|
return "C2" |
|
|
|
if "PICK UP" in nm: |
|
if cc <= 2400: |
|
return "DP" |
|
|
|
df_sample["gol"] = df_sample.apply(find_swdkllj, axis=1) |
|
|
|
|
|
df_sample["pnbp_stnk"] = df_sample["nm_jenis_kb"].apply( |
|
lambda x: 100000 if x == "SPD. MOTOR R2" else 200000 |
|
) |
|
|
|
df_sample["pnbp_tnkb"] = df_sample["nm_jenis_kb"].apply( |
|
lambda x: 60000 if x == "SPD. MOTOR R2" else 100000 |
|
) |
|
|
|
codes = """001 - Vehicle Registration (New) |
|
002 - Vehicle Registration Renewal |
|
003 - Vehicle Ownership Transfer |
|
004 - Vehicle De-registration |
|
005 - Lost Registration Certificate Replacement |
|
006 - Address Change Update |
|
007 - Vehicle Data Correction |
|
008 - Ownership Name Correction |
|
009 - Vehicle Tax Payment |
|
010 - Late Payment Fee Processing |
|
011 - Vehicle Type/Specification Update |
|
012 - BBNKB (Transfer Fee of Vehicle Ownership) |
|
013 - STNK Issuance (Vehicle Registration Certificate) |
|
014 - STNK Renewal |
|
015 - Motor Vehicle Roadworthiness Inspection |
|
016 - Plate Number Renewal |
|
017 - Lost Plate Replacement |
|
018 - Vehicle Export Registration |
|
019 - Vehicle Import Registration |
|
020 - Fleet Vehicle Registration |
|
021 - Bulk Vehicle Registration Update |
|
022 - Vehicle Insurance Assistance |
|
023 - Vehicle Accident Reporting |
|
024 - Vehicle Usage Change Declaration (e.g., personal to commercial) |
|
025 - Legal Document Verification |
|
026 - Ownership Transfer for Inherited Vehicle |
|
027 - STNK Temporary Suspension |
|
028 - Proof of Ownership Document Update |
|
029 - Vehicle Ownership History Check |
|
030 - Vehicle Tax Recalculation Request |
|
031 - Tax Exemption Application (for special cases) |
|
032 - Deceased Owner’s Vehicle Ownership Transfer""".split("\n") |
|
|
|
undetected = "099 - Other/Undetected" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
codes = """001 - Pendaftaran Kendaraan |
|
002 - Pembaruan Data Kendaraan |
|
003 - Alih Kepemilikan atau Balik Nama Kendaraan |
|
004 - Pelaporan Dokumen atau Plat yang Hilang |
|
005 - Pembayaran dan Pengelolaan Pajak Kendaraan |
|
006 - Pemeriksaan dan Verifikasi Kendaraan |
|
007 - Pendaftaran Kendaraan Ekspor, Impor, atau Armada |
|
008 - Pelaporan dan Bantuan Terkait Kendaraan |
|
009 - Penangguhan atau Deklarasi Perubahan Penggunaan Kendaraan""".split("\n") |
|
|
|
codes = """003 - Alih Kepemilikan atau Balik Nama Kendaraan |
|
005 - Pembayaran dan Pengelolaan Pajak Kendaraan""".split("\n") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples = [ |
|
{"code": "001", "examples": [ |
|
"Daftarkan kendaraan baru", |
|
"Pengajuan pendaftaran kendaraan", |
|
"Ajukan pendaftaran kendaraan", |
|
"Serahkan pendaftaran kendaraan baru", |
|
"Permintaan pendaftaran kendaraan baru" |
|
]}, |
|
{"code": "002", "examples": [ |
|
"Perbarui informasi kendaraan", |
|
"Ubah detail kendaraan yang terdaftar", |
|
"Ajukan pembaruan data kendaraan", |
|
"Permintaan pembaruan data kendaraan", |
|
"Modifikasi informasi pendaftaran kendaraan" |
|
]}, |
|
{"code": "003", "examples": [ |
|
"Alihkan kepemilikan kendaraan", |
|
"Ajukan perubahan nama kendaraan", |
|
"Permintaan pengalihan kepemilikan kendaraan", |
|
"Serahkan perubahan kepemilikan kendaraan", |
|
"Proses alih nama kendaraan" |
|
]}, |
|
{"code": "004", "examples": [ |
|
"Laporkan dokumen kendaraan hilang (STNK, BPKB, dll)", |
|
"Nyatakan plat nomor hilang", |
|
"Ajukan laporan dokumen kendaraan hilang", |
|
"Pelaporan dokumen kendaraan yang hilang", |
|
"Informasikan pihak berwenang tentang dokumen kendaraan yang hilang" |
|
]}, |
|
{"code": "005", "examples": [ |
|
"Bayar pajak kendaraan", |
|
"Kelola pembayaran pajak kendaraan", |
|
"Ajukan pembayaran pajak kendaraan", |
|
"Permintaan layanan manajemen pajak kendaraan", |
|
"Selesaikan pajak tahunan kendaraan" |
|
]}, |
|
{"code": "006", "examples": [ |
|
"Lakukan pemeriksaan kendaraan", |
|
"Ajukan pemeriksaan verifikasi kendaraan", |
|
"Serahkan kendaraan untuk verifikasi", |
|
"Jadwalkan pemeriksaan kendaraan", |
|
"Ajukan inspeksi dan verifikasi kendaraan" |
|
]}, |
|
{"code": "007", "examples": [ |
|
"Daftarkan kendaraan impor", |
|
"Ajukan pendaftaran kendaraan ekspor", |
|
"Ajukan pendaftaran kendaraan armada", |
|
"Daftarkan kendaraan baru untuk ekspor atau impor", |
|
"Pengajuan pendaftaran kendaraan armada" |
|
]}, |
|
{"code": "008", "examples": [ |
|
"Laporkan masalah terkait kendaraan", |
|
"Permintaan bantuan untuk masalah kendaraan", |
|
"Ajukan laporan mengenai kendaraan", |
|
"Ajukan dukungan terkait kendaraan", |
|
"Cari bantuan terkait permasalahan kendaraan" |
|
]}, |
|
{"code": "009", "examples": [ |
|
"Tangguhkan penggunaan kendaraan", |
|
"Nyatakan perubahan tujuan penggunaan kendaraan", |
|
"Ajukan penangguhan penggunaan kendaraan", |
|
"Ajukan perubahan penggunaan kendaraan", |
|
"Ajukan penangguhan operasional kendaraan" |
|
]} |
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vehicle_tax_info = { |
|
"B 1234 BCA": { |
|
"no_rangka": "1237191234", |
|
"type": "SUV", |
|
"tanggal": "23 Desember 2024", |
|
"status": "Belum Bayar", |
|
"harga_jual": 500_000_000 |
|
}, |
|
"B 5678 XYZ": { |
|
"no_rangka": "9876543210", |
|
"type": "Sedan", |
|
"tanggal": "15 Januari 2025", |
|
"status": "Belum Bayar", |
|
"harga_jual": 375_800_000 |
|
}, |
|
"D 3456 DEF": { |
|
"no_rangka": "4561237890", |
|
"type": "MPV", |
|
"tanggal": "10 Februari 2025", |
|
"status": "Sudah Bayar", |
|
"harga_jual": 400_000_000 |
|
} |
|
} |
|
|
|
|
|
detail_perhitungan = { |
|
"001": { |
|
"name": "Pendaftaran Kendaraan", |
|
"formula": lambda harga_jual: harga_jual * 0.1, |
|
|
|
}, |
|
"002": { |
|
"name": "Pembaruan Data Kendaraan", |
|
"formula": lambda harga_jual: harga_jual * 0.05, |
|
|
|
}, |
|
"003": { |
|
"name": "Alih Kepemilikan (Balik Nama) Kendaraan", |
|
"formula": lambda harga_jual: harga_jual * 0.1, |
|
|
|
}, |
|
"004": { |
|
"name": "Penggantian Dokumen atau Plat yang Hilang", |
|
"formula": lambda harga_jual: harga_jual * 0.03, |
|
|
|
}, |
|
"005": { |
|
"name": "Pembayaran dan Pengelolaan Pajak Kendaraan", |
|
"formula": lambda harga_jual: harga_jual * 0.12, |
|
|
|
}, |
|
"006": { |
|
"name": "Pemeriksaan dan Verifikasi Kendaraan", |
|
"formula": lambda harga_jual: 100000, |
|
|
|
}, |
|
"007": { |
|
"name": "Pendaftaran Kendaraan Ekspor, Impor, atau Armada", |
|
"formula": lambda harga_jual: harga_jual * 0.15, |
|
|
|
}, |
|
"008": { |
|
"name": "Pelaporan dan Bantuan Terkait Kendaraan", |
|
"formula": lambda harga_jual: harga_jual * 0.04, |
|
|
|
}, |
|
"009": { |
|
"name": "Penangguhan atau Deklarasi Perubahan Penggunaan Kendaraan", |
|
"formula": lambda harga_jual: harga_jual * 0.06, |
|
|
|
} |
|
} |
|
|
|
undetected = "099 - Lainnya/Tidak Terdeteksi" |
|
|
|
model_ids = [ |
|
"BAAI/bge-m3", |
|
"sentence-transformers/paraphrase-multilingual-mpnet-base-v2", |
|
"intfloat/multilingual-e5-small", |
|
"sentence-transformers/distiluse-base-multilingual-cased-v2", |
|
"Alibaba-NLP/gte-multilingual-base", |
|
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", |
|
"jinaai/jina-reranker-v2-base-multilingual", |
|
"BAAI/bge-reranker-v2-m3", |
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
model_id = model_ids[-1] |
|
model = None |
|
codes_emb = None |
|
|
|
def load_model(model_id): |
|
|
|
|
|
if model_id in model_ids[-2:]: |
|
model = CrossEncoder( |
|
|
|
|
|
model_id, |
|
automodel_args={"torch_dtype": "auto"}, |
|
trust_remote_code=True, |
|
) |
|
return model, None |
|
else: |
|
model = SentenceTransformer(model_id, trust_remote_code=True) |
|
codes_emb = model.encode([x[6:] for x in codes]) |
|
|
|
|
|
return model, codes_emb |
|
|
|
model, codes_emb = load_model(model_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
def censor_middle(number, num_to_hide=4): |
|
number_str = str(number) |
|
if num_to_hide == -1: |
|
num_to_hide = int(len(number_str)*0.8) |
|
middle_index = len(number_str) // 2 |
|
start_index = middle_index - num_to_hide // 2 |
|
end_index = middle_index + num_to_hide // 2 |
|
|
|
censored_part = "\*" * num_to_hide |
|
censored_number = number_str[:start_index] + censored_part + number_str[end_index:] |
|
|
|
return censored_number |
|
|
|
|
|
def get_calculation(request_code, plate_number): |
|
print(request_code, plate_number, "GET CALC") |
|
calc = detail_perhitungan.get(request_code) |
|
vehicle = vehicle_tax_info.get(plate_number) |
|
|
|
if vehicle != None and calc != None: |
|
harga_jual = vehicle.get("harga_jual") |
|
formula = calc.get("formula") |
|
result = formula(harga_jual) |
|
description = inspect.getsource(formula).split(":", 2)[-1].strip() |
|
result_detail = request_code + " - " + calc.get("name") |
|
return result, str(description), result_detail |
|
|
|
elif calc != None: |
|
formula = calc.get("formula") |
|
description = inspect.getsource(formula).split(":", 2)[-1].strip() |
|
result_detail = request_code + " - " + calc.get("name") |
|
return None, str(description), result_detail |
|
|
|
else: |
|
return None, None, None |
|
|
|
|
|
def build_output_formula(descriptions, result_details): |
|
out = "----------------------------------------------------\n\n" |
|
out = "Daftar Kode Permohonan:\n" |
|
for i, (desc,detail) in enumerate(zip(descriptions, result_details)): |
|
|
|
out += f"{i+1}. {detail}\nRumus: {desc}\n" |
|
return out |
|
|
|
|
|
def build_output_vehicle(plate_number): |
|
vehicle = vehicle_tax_info.get(plate_number).copy() |
|
out = "----------------------------------------------------\n\n" |
|
out = "Nomor Polisi: " + plate_number + "\n" |
|
vehicle["no_rangka"] = censor_middle(vehicle["no_rangka"]) |
|
vehicle["harga_jual"] = "Rp{:,}".format(vehicle["harga_jual"]) |
|
out += "\n".join([k + " : " + str(v) for k,v in vehicle.items()]) |
|
return out |
|
|
|
def build_output(result, description, result_detail, plate_number): |
|
return build_outputs([result], [description], [result_detail], plate_number) |
|
|
|
|
|
def build_outputs(results, descriptions, result_details, plate_number): |
|
vehicle = vehicle_tax_info.get(plate_number).copy() |
|
vehicle["harga_jual"] = "Rp{:,}".format(vehicle["harga_jual"]) |
|
|
|
out = "----------------------------------------------------\n\n" |
|
out = "Nomor Polisi: " + plate_number + "\n" |
|
out += "\n".join([k + " : " + str(v) if k != "no_rangka" else k + " : " + censor_middle(v) for k,v in vehicle.items()]) |
|
|
|
|
|
|
|
out += "\n\nDaftar Kode Permohonan:\n" |
|
|
|
for i, (res,desc,detail) in enumerate(zip(results, descriptions, result_details)): |
|
harga_jual = vehicle["harga_jual"] |
|
res_str = "{:,}".format(res) |
|
out += f"{i+1}. {detail}\nRumus: {desc}\nDetail perhitungan: {desc.replace('harga_jual', harga_jual)} = Rp{res_str}\n" |
|
|
|
|
|
out += "\n\n\nEstimasi Biaya: " |
|
|
|
if len(results) > 1: |
|
out += " + ".join(["Rp{:,}".format(x) for x in results]) |
|
out += " = Rp{:,}".format(sum(results)) |
|
else: |
|
out += "Rp{:,}".format(results[0]) |
|
|
|
out += "\n\n----------------------------" |
|
|
|
return out |
|
|
|
|
|
app = FastAPI() |
|
|
|
@app.post("/pred") |
|
async def greet_json( |
|
message : str, |
|
threshold : float = 0.0005, |
|
tarif_pkb : float = 0.015, |
|
tarif_bbnkb : float = 0.1, |
|
): |
|
global codes_emb |
|
global undetected |
|
|
|
undetected_code = undetected[:3] |
|
|
|
|
|
|
|
|
|
pattern = r'\b([A-Za-z]{1,2})\s?(\d{2,4})\s?([A-Za-z]{1,3})\b' |
|
|
|
matches = re.findall(pattern, message) |
|
|
|
plates = [" ".join(x).upper() for i,x in enumerate(matches)] |
|
|
|
|
|
if type(model) == CrossEncoder: |
|
sentence_pairs = [[message, v[6:]] for v in codes] |
|
scores = model.predict(sentence_pairs, convert_to_tensor=True) |
|
weights = [9,8] |
|
else: |
|
text_emb = model.encode(message) |
|
scores = cos_sim(codes_emb, text_emb).mean(axis=-1) |
|
weights = [11,9] |
|
|
|
scores_argsort = scores.argsort(descending=True) |
|
w_avg = np.average(scores[scores_argsort].numpy(), weights=weights) |
|
|
|
|
|
out = "" |
|
|
|
for inp in plates: |
|
|
|
vehicle = df_sample[df_sample["no_polisi"] == inp.strip()].copy() |
|
|
|
if vehicle.shape[0] == 0: |
|
out += f"\n\n---\nKendaraan {inp} Tidak Ditemukan\n" |
|
else: |
|
vehicle["nm_pemilik"] = censor_middle(vehicle["nm_pemilik"].values[0], -1) |
|
vehicle["al_pemilik"] = censor_middle(vehicle["al_pemilik"].values[0], -1) |
|
|
|
v_type = vehicle["nm_jenis_kb"].values[0] |
|
nilai_jual = vehicle["nilai_jual"].values[0] |
|
pnbp_stnk = vehicle["pnbp_stnk"].values[0] |
|
pnbp_tnkb = vehicle["pnbp_tnkb"].values[0] |
|
|
|
bobot = df_bobot[df_bobot["JENIS_KENDARAAN"]==v_type]["BOBOT"].values[0] |
|
|
|
bbnkb = tarif_bbnkb * nilai_jual * 1 |
|
pkb = tarif_pkb * bobot * nilai_jual * 1 |
|
|
|
vehicle["nilai_jual"] = f"Rp{int(nilai_jual):,}" |
|
out += "\n\n---\nDetail Kendaraan:" |
|
for k,v in vehicle.iloc[0].items(): |
|
out += f"\n{k} \t\t: {v}" |
|
|
|
|
|
out += "\n--" |
|
|
|
if scores[scores_argsort[0]] < threshold: |
|
continue |
|
|
|
header_rincian = "| POKOK | DENDA | TOTAL ||\n|-:|-:|-:|:-|\n" |
|
rincian = "\n\n### RINCIAN:\n\n" + header_rincian |
|
|
|
is_rincian = False |
|
|
|
out_k = "" |
|
|
|
if scores[0] > w_avg: |
|
out += f"\nBBNKB \t\t: {int(bbnkb):,}" |
|
|
|
out_k += "\nRumus Bea Balik Nama Kendaraan Bermotor (BBNKB) : TARIF x NJKB x PENGENAAN" |
|
out_k += f"\nKalkulasi : {tarif_bbnkb*100}% x Rp{int(nilai_jual):,} x 100%" |
|
out_k += f"\nTotal Pembayaran : Rp{int(bbnkb):,}\n" |
|
rincian += f"|{int(bbnkb):,}|0|{int(bbnkb):,}|BBNKB|\n" |
|
is_rincian = True |
|
else: |
|
bbnkb = 0 |
|
|
|
if scores[1] > w_avg: |
|
d = datetime.now().date() - vehicle["tg_akhir_pkb"].values[0] |
|
d = d.days // 365 |
|
if d < 1: |
|
d = 1 |
|
|
|
swdkllj = dict_swdkllj.get(vehicle["gol"].values[0]) |
|
|
|
out += f"\nPKB \t\t: {int(pkb*d):,}" |
|
out += f"\nSWDKLLJ \t\t: {int(swdkllj*d):,}" |
|
out += f"\nPNBP STNK \t\t:{int(pnbp_stnk):,}" |
|
out += f"\nPNBP TNKB \t\t:{int(pnbp_tnkb):,}" |
|
out += f"\nTOTAL \t\t: {int(pkb*d + swdkllj*d + pnbp_stnk + pnbp_tnkb + bbnkb):,}" |
|
|
|
out_k += "\nRumus Pokok Pajak Kendaraan Bermotor (PKB) : TARIF * NJKB * BOBOT * PENGENAAN * TAHUN BAYAR" |
|
out_k += f"\nKalkulasi : {tarif_pkb*100}% * Rp{int(nilai_jual):,} * {bobot} * 100% * {d}" |
|
out_k += f"\nTotal Pembayaran : Rp{int(pkb*d):,}\n" |
|
out_k += "\nRumus Total PKB: PKB + SWDKLLJ + PNBP STNK + PNBP TNKB" |
|
out_k += f"\nKalkulasi : Rp{int(pkb*d):,} + Rp{int(swdkllj*d):,} + Rp{int(pnbp_stnk):,} + Rp{int(pnbp_tnkb):,}" |
|
out_k += f"\nTotal Pembayaran : Rp{int(pkb*d + swdkllj*d + pnbp_stnk + pnbp_tnkb):,}\n" |
|
|
|
rincian += f"|{int(pkb*d):,}|0|{int(pkb*d):,}|PKB|\n" + f"|{int(swdkllj*d):,}|0|{int(swdkllj*d):,}|SWDKLLJ|\n\n" |
|
rincian_pkb = "### RINCIAN PKB:\n\n| POKOK | DENDA | TOTAL |\n|-:|-:|-:|\n" |
|
rincian_swdkllj = "### RINCIAN SWDKLLJ:\n\n| POKOK | DENDA | TOTAL |\n|-:|-:|-:|\n" |
|
for i in range(d): |
|
rincian_pkb += f"|{int(pkb):,}|0|{int(pkb):,}|PKB|\n" |
|
rincian_swdkllj += f"|{int(swdkllj):,}|0|{int(swdkllj):,}|PKB|\n" |
|
rincian += rincian_pkb + "\n" + rincian_swdkllj |
|
is_rincian = True |
|
out += out_k |
|
if is_rincian: |
|
out += rincian |
|
if not out and scores[scores_argsort[0]] >= threshold: |
|
if scores[0] > w_avg: |
|
out += "\nRumus Bea Balik Nama Kendaraan Bermotor (BBNKB) : TARIF x NJKB x PENGENAAN" |
|
if scores[1] > w_avg: |
|
out += "\nRumus Pokok Pajak Kendaraan Bermotor (PKB) : TARIF * NJKB * BOBOT * PENGENAAN" |
|
|
|
return {"results":out} |