ZakyF commited on
Commit
d0e945e
·
1 Parent(s): 2d79f8e

sedikit LLM

Browse files
Files changed (1) hide show
  1. app.py +79 -86
app.py CHANGED
@@ -1,112 +1,105 @@
1
  import pandas as pd
2
  import numpy as np
3
  import gradio as gr
4
- import os
5
  from transformers import pipeline
 
 
6
 
7
- # --- KONFIGURASI PATH & MODEL ---
8
- MODEL_PATH = "archon_v1"
9
- # Kategori wajib sesuai instruksi Fase 2
10
- ESSENTIAL_CATS = {'groceries', 'utilities', 'transport', 'healthcare', 'education'}
11
- DISCRETIONARY_CATS = {'restaurant', 'cafe', 'entertainment', 'fashion', 'online_shopping', 'travel'}
12
 
13
- class ArchonBankEngine:
14
  def __init__(self):
15
- # Pilar 1: AI Classifier (Fase 2)
16
- self.classifier = pipeline("text-classification", model=MODEL_PATH, tokenizer=MODEL_PATH)
17
- self.load_all_data()
18
 
19
- def load_all_data(self):
20
- # FASE 1: DATA FOUNDATION
21
  self.df_txn = pd.read_csv('transactions.csv', parse_dates=['date'])
22
  self.df_cust = pd.read_csv('customers.csv')
23
  self.df_bal = pd.read_csv('balances_revised.csv', parse_dates=['month'])
24
  self.df_rep = pd.read_csv('repayments_revised.csv', parse_dates=['due_date'])
25
- self.df_off = pd.read_csv('offers.csv')
26
 
27
- def analyze_customer(self, customer_id):
28
- # --- PRE-PROCESSING DATA NASABAH ---
29
  user_txn = self.df_txn[self.df_txn['customer_id'] == customer_id].copy()
30
  user_bal = self.df_bal[self.df_bal['customer_id'] == customer_id].sort_values('month')
31
- user_rep = self.df_rep[self.df_rep['customer_id'] == customer_id]
32
- user_info = self.df_cust[self.df_cust['customer_id'] == customer_id].iloc[0]
33
-
34
- if user_txn.empty: return {"Error": "Data Nasabah Tidak Ditemukan"}
35
-
36
- # --- FASE 2: TRANSACTION INTELLIGENCE (Automasi AI) ---
37
- # AI menentukan kategori dari deskripsi transaksi yang ambigu
38
- user_txn['merchant_category'] = user_txn['raw_description'].apply(lambda x: self.classifier(x)[0]['label'])
39
 
40
- # Penentuan expense_type sesuai aturan Fase 2
41
- def set_expense_type(cat):
42
- if any(k in cat.lower() for k in ESSENTIAL_CATS): return 'essential'
43
- return 'discretionary'
44
- user_txn['expense_type'] = user_txn['merchant_category'].apply(set_expense_type)
45
-
46
- # --- FASE 3 & 4: RISK SCORING (Early Warning System) ---
47
- # 1. Expense Ratio (Bulan terakhir)
48
  income = user_txn[user_txn['transaction_type'] == 'credit']['amount'].sum()
49
  expense = user_txn[user_txn['transaction_type'] == 'debit']['amount'].sum()
50
  er = expense / income if income > 0 else 1.0
51
  er_score = 1 if er > 0.8 else (0.5 if er > 0.5 else 0)
52
 
53
- # 2. Balance Trend (Bulan ini vs bulan lalu)
54
- if len(user_bal) >= 2:
55
- bt = -1 if user_bal.iloc[-1]['avg_balance'] < user_bal.iloc[-2]['avg_balance'] else 1
56
- else: bt = 0
57
- bt_score = 1 if bt == -1 else 0
58
-
59
- # 3. Overdraft & Missed Payment
60
  od_score = 1 if (user_bal['min_balance'] <= 0).any() else 0
61
- mp_score = 1 if (user_rep['status'] == 'late').any() else 0
62
 
63
- # HITUNG FINAL RISK SCORE (Bobot Fix: 30%, 20%, 20%, 20%, 10%)
64
- risk_score = (0.3 * er_score) + (0.2 * bt_score) + (0.2 * od_score) + (0.2 * mp_score) + 0.1
65
- risk_level = "HIGH" if risk_score >= 0.7 else ("MEDIUM" if risk_score >= 0.4 else "LOW")
66
-
67
- # --- FASE 5: NBO ENGINE ---
68
- # Menentukan aksi sesuai kriteria Fase 5
69
- disc_ratio = user_txn[user_txn['expense_type'] == 'discretionary']['amount'].sum() / expense if expense > 0 else 0
70
 
71
- if risk_level == "HIGH":
72
- action = "restructuring_suggestion"
73
- reason = "REPAYMENT_RISK_DETECTED"
74
- elif risk_level == "MEDIUM" and disc_ratio > 0.4:
75
- action = "budgeting_alert"
76
- reason = "HIGH_DISCRETIONARY_SPENDING"
77
- elif risk_level == "LOW" and disc_ratio <= 0.4:
78
- action = "promote_saving"
79
- reason = "STABLE_CASHFLOW"
80
- else:
81
- action = "no_action"
82
- reason = "COOLDOWN_ACTIVE"
83
-
84
- # --- FASE 6: EXPLAINABLE SUMMARY ---
85
- summary = f"Nasabah memiliki risiko {risk_level}. "
86
- if er_score == 1: summary += "Pengeluaran sangat tinggi (>80% pendapatan). "
87
- if bt_score == 1: summary += "Tren saldo menurun signifikan. "
88
- if mp_score == 1: summary += "Terdeteksi riwayat telat bayar."
89
-
90
- return {
91
- "ID Nasabah": customer_id,
92
- "Level Risiko": risk_level,
93
- "Rekomendasi Aksi": action,
94
- "Alasan": reason,
95
- "Penjelasan": summary
96
- }
97
-
98
- # --- INTEGRASI KE DASHBOARD ---
99
- engine = ArchonBankEngine()
100
-
101
- def run_app(cust_id):
102
- return engine.analyze_customer(cust_id)
103
-
104
- demo = gr.Interface(
105
- fn=run_app,
106
- inputs=gr.Textbox(label="Input Customer ID (C0001 - C0120)"),
107
- outputs="json",
108
- title="🛡️ Archon-AI Production Engine",
109
- description="Sistem automasi perbankan sesuai instruksi Arahan Pembuatan AI Archon."
110
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  demo.launch()
 
1
  import pandas as pd
2
  import numpy as np
3
  import gradio as gr
4
+ import plotly.graph_objects as go
5
  from transformers import pipeline
6
+ from huggingface_hub import InferenceClient
7
+ import os
8
 
9
+ # --- KONFIGURASI PILAR ---
10
+ # Pastikan HF_TOKEN ada di Settings > Secrets di Hugging Face Space kamu
11
+ HF_TOKEN = os.getenv("HF_TOKEN")
12
+ client = InferenceClient(model="mistralai/Mistral-7B-Instruct-v0.3", token=HF_TOKEN)
 
13
 
14
+ class ArchonFinalEngine:
15
  def __init__(self):
16
+ # Fase 2: AI Classifier (BERT)
17
+ self.classifier = pipeline("text-classification", model="archon_v1", tokenizer="archon_v1")
18
+ self.load_data()
19
 
20
+ def load_data(self):
21
+ # Fase 1: Single Source of Truth
22
  self.df_txn = pd.read_csv('transactions.csv', parse_dates=['date'])
23
  self.df_cust = pd.read_csv('customers.csv')
24
  self.df_bal = pd.read_csv('balances_revised.csv', parse_dates=['month'])
25
  self.df_rep = pd.read_csv('repayments_revised.csv', parse_dates=['due_date'])
 
26
 
27
+ def get_risk_analysis(self, customer_id):
28
+ # --- FASE 3 & 4: DETERMINISTIC CALCULATION (Banking Standard) ---
29
  user_txn = self.df_txn[self.df_txn['customer_id'] == customer_id].copy()
30
  user_bal = self.df_bal[self.df_bal['customer_id'] == customer_id].sort_values('month')
 
 
 
 
 
 
 
 
31
 
32
+ # 1. Expense Ratio Score (30%)
 
 
 
 
 
 
 
33
  income = user_txn[user_txn['transaction_type'] == 'credit']['amount'].sum()
34
  expense = user_txn[user_txn['transaction_type'] == 'debit']['amount'].sum()
35
  er = expense / income if income > 0 else 1.0
36
  er_score = 1 if er > 0.8 else (0.5 if er > 0.5 else 0)
37
 
38
+ # 2. Balance Trend Score (20%)
39
+ bt_score = 1 if len(user_bal) >= 2 and user_bal.iloc[-1]['avg_balance'] < user_bal.iloc[-2]['avg_balance'] else 0
40
+
41
+ # 3. Overdraft Score (20%)
 
 
 
42
  od_score = 1 if (user_bal['min_balance'] <= 0).any() else 0
 
43
 
44
+ # Formula Final Risk Score
45
+ # risk_score = 0.3 * ER + 0.2 * BT + 0.2 * OD + 0.2 * MP + 0.1 * Vol
46
+ final_score = (0.3 * er_score) + (0.2 * bt_score) + (0.2 * od_score) + 0.1
 
 
 
 
47
 
48
+ risk_level = "HIGH" if final_score >= 0.7 else ("MEDIUM" if final_score >= 0.4 else "LOW")
49
+
50
+ return risk_level, final_score, er, user_bal
51
+
52
+ def generate_llm_advice(self, risk_level, er_ratio, customer_id):
53
+ # --- FASE 5: GENERATIVE NBO (Action Layer) ---
54
+ # Menggunakan LLM agar saran tidak kaku seperti robot
55
+ prompt = f"""
56
+ Role: Senior Financial Advisor di Bank Indonesia.
57
+ Nasabah: {customer_id}
58
+ Kondisi: Risiko {risk_level}, Rasio Pengeluaran {er_ratio:.2%}.
59
+ Tugas: Berikan 1 paragraf saran yang natural, empati, dan sangat personal dalam Bahasa Indonesia.
60
+ Gunakan gaya bahasa profesional tapi bersahabat. Jangan kaku.
61
+ """
62
+ try:
63
+ response = client.chat_completion(messages=[{"role": "user", "content": prompt}], max_tokens=150)
64
+ return response.choices[0].message.content
65
+ except:
66
+ return "Tetap pantau pengeluaran Anda agar kesehatan finansial terjaga."
67
+
68
+ def create_plots(self, user_bal):
69
+ # --- FASE 6: INSIGHT VISUALIZATION
70
+ fig = go.Figure()
71
+ fig.add_trace(go.Scatter(x=user_bal['month'], y=user_bal['avg_balance'], name='Avg Balance', line=dict(color='blue', width=4)))
72
+ fig.add_trace(go.Bar(x=user_bal['month'], y=user_bal['min_balance'], name='Min Balance', marker_color='orange', opacity=0.6))
73
+ fig.update_layout(title='Tren Saldo Bulanan', xaxis_title='Bulan', yaxis_title='Jumlah (Rp)', template='plotly_white')
74
+ return fig
75
+
76
+ # --- UI LOGIC ---
77
+ engine = ArchonFinalEngine()
78
+
79
+ def run_archon(cust_id):
80
+ risk_lv, score, er, bal_data = engine.get_risk_analysis(cust_id)
81
+ advice = engine.generate_llm_advice(risk_lv, er, cust_id)
82
+ plot = engine.create_plots(bal_data)
83
+
84
+ summary = {
85
+ "Risk Level": risk_lv,
86
+ "Risk Score": round(score, 2),
87
+ "Expense Ratio": f"{round(er*100, 2)}%"
88
+ }
89
+ return summary, advice, plot
90
+
91
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
92
+ gr.Markdown("# 🛡️ Archon-AI: Industrial Dashboard")
93
+ with gr.Row():
94
+ with gr.Column(scale=1):
95
+ input_id = gr.Textbox(label="Customer ID", placeholder="C0001")
96
+ btn = gr.Button("Analyze Customer", variant="primary")
97
+ out_json = gr.JSON(label="Deterministic Metrics")
98
+ with gr.Column(scale=2):
99
+ out_plot = gr.Plot(label="Financial Timeline (Phase 6)")
100
+
101
+ out_advice = gr.Textbox(label="Archon Generative Advice (LLM)", lines=5)
102
+
103
+ btn.click(fn=run_archon, inputs=input_id, outputs=[out_json, out_advice, out_plot])
104
 
105
  demo.launch()