Spaces:
Sleeping
Sleeping
import gradio as gr | |
import re | |
import inspect | |
from sentence_transformers import SentenceTransformer | |
from sentence_transformers.util import cos_sim | |
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 (Baru) | |
# 002 - Pembaruan Pendaftaran Kendaraan | |
# 003 - Alih Kepemilikan Kendaraan | |
# 004 - Pembatalan Pendaftaran Kendaraan | |
# 005 - Penggantian Sertifikat Pendaftaran Kendaraan yang Hilang | |
# 006 - Pembaruan Perubahan Alamat | |
# 007 - Koreksi Data Kendaraan | |
# 008 - Koreksi Nama Kepemilikan | |
# 009 - Pembayaran Pajak Kendaraan | |
# 010 - Proses Denda Keterlambatan Pembayaran | |
# 011 - Pembaruan Jenis/Spesifikasi Kendaraan | |
# 012 - Pembayaran Pajak Kendaraan Melalui E-Samsat | |
# 013 - Penerbitan STNK (Sertifikat Pendaftaran Kendaraan) | |
# 014 - Pembaruan STNK | |
# 015 - Pemeriksaan Kelayakan Jalan Kendaraan Bermotor | |
# 016 - Pembaruan Nomor Plat Kendaraan | |
# 017 - Penggantian Plat yang Hilang | |
# 018 - Pendaftaran Ekspor Kendaraan | |
# 019 - Pendaftaran Impor Kendaraan | |
# 020 - Pendaftaran Kendaraan Armada | |
# 021 - Pembaruan Pendaftaran Kendaraan Massal | |
# 022 - Bantuan Asuransi Kendaraan | |
# 023 - Pelaporan Kecelakaan Kendaraan | |
# 024 - Deklarasi Perubahan Penggunaan Kendaraan (misalnya, pribadi ke komersial) | |
# 025 - Verifikasi Dokumen Hukum | |
# 026 - Alih Kepemilikan Kendaraan Warisan | |
# 027 - Penangguhan Sementara STNK | |
# 028 - Pembaruan Dokumen Bukti Kepemilikan | |
# 029 - Pemeriksaan Riwayat Kepemilikan Kendaraan | |
# 030 - Permintaan Perhitungan Ulang Pajak Kendaraan | |
# 031 - Permohonan Pembebasan Pajak (untuk kasus khusus) | |
# 032 - Alih Kepemilikan Kendaraan Pemilik yang Meninggal""".split("\n") | |
codes = """001 - Pendaftaran Kendaraan | |
002 - Pembaruan Data Kendaraan | |
003 - Alih atau Pembatalan Kepemilikan | |
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") | |
vehicle_tax_info = { | |
"B 1234 BCA": { | |
"no_rangka": "1237191234", | |
"type": "SUV", | |
"tanggal": "23 Desember 2024", | |
"status": "Belum Bayar", | |
"harga_jual": 150000 # In Rupiah | |
}, | |
"B 5678 XYZ": { | |
"no_rangka": "9876543210", | |
"type": "Sedan", | |
"tanggal": "15 Januari 2025", | |
"status": "Belum Bayar", | |
"harga_jual": 300000 # In Rupiah | |
}, | |
"D 3456 DEF": { | |
"no_rangka": "4561237890", | |
"type": "MPV", | |
"tanggal": "10 Februari 2025", | |
"status": "Sudah Bayar", | |
"harga_jual": 250000 # In Rupiah | |
} | |
} | |
# Table for detail calculations (perhitungan) | |
detail_perhitungan = { | |
"001": { | |
"name": "Pendaftaran Kendaraan", | |
"formula": lambda harga_jual: harga_jual * 0.1, | |
# Example formula: 10% of harga_jual | |
}, | |
"002": { | |
"name": "Pembaruan Data Kendaraan", | |
"formula": lambda harga_jual: harga_jual * 0.05, | |
# Example formula: 5% of harga_jual | |
}, | |
"003": { | |
"name": "Alih Kepemilikan Kendaraan", | |
"formula": lambda harga_jual: harga_jual * 0.1, | |
# Example formula: 10% of harga_jual | |
}, | |
"004": { | |
"name": "Penggantian Dokumen atau Plat yang Hilang", | |
"formula": lambda harga_jual: harga_jual * 0.03, | |
# Example formula: 3% of harga_jual | |
}, | |
"005": { | |
"name": "Pembayaran dan Pengelolaan Pajak Kendaraan", | |
"formula": lambda harga_jual: harga_jual * 0.12, | |
# Example formula: 12% of harga_jual | |
}, | |
"006": { | |
"name": "Pemeriksaan dan Verifikasi Kendaraan", | |
"formula": lambda harga_jual: 100000, | |
# Example formula: 2% of harga_jual | |
}, | |
"007": { | |
"name": "Pendaftaran Kendaraan Ekspor, Impor, atau Armada", | |
"formula": lambda harga_jual: harga_jual * 0.15, | |
# Example formula: 15% of harga_jual | |
}, | |
"008": { | |
"name": "Pelaporan dan Bantuan Terkait Kendaraan", | |
"formula": lambda harga_jual: harga_jual * 0.04, | |
# Example formula: 4% of harga_jual | |
}, | |
"009": { | |
"name": "Penangguhan atau Deklarasi Perubahan Penggunaan Kendaraan", | |
"formula": lambda harga_jual: harga_jual * 0.06, | |
# Example formula: 6% of harga_jual | |
} | |
} | |
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", | |
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", | |
"Alibaba-NLP/gte-multilingual-base", | |
] | |
# model_id = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" | |
# model_id = "Alibaba-NLP/gte-multilingual-base" | |
# model_id = "BAAI/bge-m3" | |
# model_id = "sentence-transformers/paraphrase-multilingual-mpnet-base-v2" | |
# model_id = "intfloat/multilingual-e5-small" | |
# model_id = "sentence-transformers/distiluse-base-multilingual-cased-v2" | |
model_id = model_ids[-1] | |
model = SentenceTransformer(model_id, trust_remote_code=True) | |
codes_emb = model.encode([x[6:] for x in codes]) | |
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 or calc == None: | |
return None, None, 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") | |
# out = "==============================================" | |
# out += "\nWajib Pajak ingin melakukan proses berikut:\n" | |
# out = "" | |
return result, str(description), result_detail | |
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): | |
out = "--------------------------------------------------" | |
vehicle = vehicle_tax_info.get(plate_number) | |
out = "\nPlate Number: " + plate_number + "\n" | |
out += "\n".join([k + " : " + str(v) for k,v in vehicle.items()]) | |
out += "\n----------------------------------------------" | |
out += f"\nWajib Pajak dengan NoPol {plate_number} ingin melakukan proses berikut:\n" | |
for i, (res,desc,detail) in enumerate(zip(results, descriptions, result_details)): | |
out += f"{i+1}. {detail}\nDetail perhitungan: {desc.replace('harga_jual', str(res))}\n" | |
out += "Estimasi biaya: " | |
if len(results) > 1: | |
out += " + ".join([f"Rp{x}" for x in results]) | |
out += f" = {sum(results)}" | |
else: | |
out += str(results[0]) | |
return out | |
def respond( | |
message, | |
history: list[tuple[str, str]], | |
threshold, | |
is_multiple | |
): | |
global codes_emb | |
global undetected | |
undetected_code = undetected[:3] | |
if history and history[-1][-1][21:24] == undetected_code: | |
list_his = "" | |
for his in history[::-1]: | |
if his[-1][21:24] != undetected_code: | |
break | |
list_his = his[0] + "\n" + list_his | |
message += "\n" + list_his | |
# pattern = r'\b([A-Z]{1,2})\s?(\d{4})\s?([A-Z]{3})\b' | |
# pattern = r'\b([A-Z]{1,2})\s?(\d{4})\s?([A-Z]{1,3})\b' | |
pattern = r'\b([A-Za-z]{1,2})\s?(\d{4})\s?([A-Za-z]{1,3})\b' | |
matches = re.findall(pattern, message) | |
plates = [" ".join(x).upper() for i,x in enumerate(matches)] | |
plate_numbers = ", ".join(plates) | |
text_emb = model.encode(message) | |
scores = cos_sim(codes_emb, text_emb)[:,0] | |
if is_multiple: | |
request_details = [] | |
request_numbers = [] | |
request_scores = [] | |
for i,score in enumerate(scores): | |
if score > threshold: | |
request_details.append(codes[i][6:]) | |
request_numbers.append(codes[i][:3]) | |
request_scores.append(str( round(score.tolist(), 3) ) ) | |
if not request_details: | |
request_details.append(undetected[6:]) | |
request_numbers.append(undetected_code) | |
request_numbers_copy = request_numbers | |
request_numbers = "\n".join(request_numbers) | |
request_details = "\n".join(request_details) | |
request_scores = "\n".join(request_scores) | |
out = "Request code number:\n" + request_numbers + "\n\nRequest detail:\n" + request_details + f"\n\nConfidence score:\n{request_scores}" + "\n\nPlate numbers: " + plate_numbers | |
for plate in plates: | |
results, descriptions, result_details = [], [], [] | |
for code in request_numbers_copy: | |
result, description, result_detail = get_calculation(code, plate) | |
if result != None: | |
results.append(result) | |
descriptions.append(description) | |
result_details.append(result_detail) | |
else: | |
break | |
if results: | |
out += "\n\n" + build_outputs(results, descriptions, result_details, plate) | |
return out | |
# result, description, result_detailget_calculation(request_code, plate_number) | |
s_max = scores.argmax() | |
if scores[s_max] < threshold: | |
# request_code = "033 - Other/Undetected" | |
request_code = undetected | |
else: | |
request_code = codes[scores.argmax()] | |
# "{:.2f}".format(a) | |
out = "Request code number: " + request_code[:3] + "\nRequest detail: " + request_code[6:] + f"\nConfidence score: {round(scores[s_max].tolist(),3)}" + "\nPlate numbers: " + plate_numbers | |
for plate in plates: | |
results, descriptions, result_details = [], [], [] | |
result, description, result_detail = get_calculation(request_code[:3], plate) | |
if result != None: | |
results.append(result) | |
descriptions.append(description) | |
result_details.append(result_detail) | |
out += "\n\n" + build_outputs(results, descriptions, result_details, plate) | |
return out | |
# if vehicle_tax_info.get(request_detail) | |
# for val in history: | |
# if val[0]: | |
# messages.append({"role": "user", "content": val[0]}) | |
# if val[1]: | |
# messages.append({"role": "assistant", "content": val[1]}) | |
# messages.append({"role": "user", "content": message}) | |
# response = "" | |
# for message in client.chat_completion( | |
# messages, | |
# max_tokens=max_tokens, | |
# stream=True, | |
# temperature=temperature, | |
# top_p=top_p, | |
# ): | |
# token = message.choices[0].delta.content | |
# response += token | |
# yield response | |
""" | |
For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface | |
""" | |
# demo = gr.ChatInterface( | |
# respond, | |
# ) | |
def reload(chosen_model_id): | |
global model | |
global model_id | |
global codes_emb | |
if chosen_model_id != model_id: | |
model = SentenceTransformer(chosen_model_id, trust_remote_code=True) | |
model_id = chosen_model_id | |
codes_emb = model.encode([x[6:] for x in codes]) | |
return f"Model {chosen_model_id} has been succesfully loaded!" | |
return f"Model {chosen_model_id} is ready!" | |
with gr.Blocks() as demo: | |
# Add header title and description | |
gr.Markdown("# List of Request Numbers") | |
gr.Markdown("<br>".join(codes) + "<br>" + undetected) | |
gr.Markdown("# Valid License Plate Number Criteria:") | |
gr.Markdown("(1-2 letters) (4 numbers) (1-3 letters)") | |
gr.Markdown("# Example Valid Plate Numbers") | |
gr.Markdown("<br>".join(vehicle_tax_info.keys())) | |
gr.Markdown("# Choose & Load Model:") | |
reload_model = gr.Interface( | |
fn=reload, | |
inputs=[gr.Dropdown(choices=model_ids, value=model_id)], | |
outputs="text", | |
# gr.HighlightedText( | |
# label="status", | |
# combine_adjacent=True, | |
# show_legend=True, | |
# color_map={"+": "red", "-": "green"} | |
# ), | |
) | |
gr.Markdown("# Chatbot Interface:") | |
chat_interface = gr.ChatInterface( | |
respond, | |
additional_inputs=[ | |
gr.Number(0.5, label="confidence threshold", show_label=True, minimum=0., maximum=1.0, step=0.1), | |
gr.Checkbox(label="multiple", info="Allow multiple request code numbers"), | |
], | |
type="messages", | |
chatbot=gr.Chatbot(height=800), | |
# textbox=gr.Textbox(placeholder="Ask me a yes or no question", container=False, scale=7), | |
# title="SamSat Virtual Assistant", | |
# description="Ask Yes Man any question", | |
# theme="soft", | |
# examples=["balik nama D 3456 DEF", "bayar pajak B 1234 BCA", "halo, selamat pagi!"], | |
# cache_examples=True, | |
) | |
if __name__ == "__main__": | |
demo.launch() | |