CoolFace
Apppublic

Arpitkr/fraud-detection-ui

sourceHugging Faceupdated 18d agoView on Hugging Face
0likes
app.py379 linesDownload Raw Back to root
1from dotenv import load_dotenv2load_dotenv()3 4import streamlit as st5import requests6import json7from groq import Groq8from src.rag_engine import rag_engine9import os10from src.knowledge_base import FRAUD_KNOWLEDGE_BASE11from collections import defaultdict12 13client = Groq(api_key=os.getenv("GROQ_API_KEY"))14 15st.set_page_config(page_title="Fraud Detection System", layout="centered")16st.title("Credit Card Fraud Detection")17st.divider()18 19sample_fraud = {20    "Time": 406.0, "V1": -2.3122, "V2": 1.9520, "V3": -1.6099,21    "V4": 3.9979, "V5": -0.5222, "V6": -1.4265, "V7": -2.5374,22    "V8": 1.3917, "V9": -2.7701, "V10": -2.7723, "V11": 3.2020,23    "V12": -2.8999, "V13": -0.5952, "V14": -4.2893, "V15": 0.3897,24    "V16": -1.1407, "V17": -2.8301, "V18": -0.0168, "V19": 0.4170,25    "V20": 0.1269, "V21": 0.5172, "V22": -0.0350, "V23": -0.4652,26    "V24": 0.3202, "V25": 0.0445, "V26": 0.1778, "V27": 0.2611,27    "V28": -0.1433, "Amount": 149.6228}29 30V_DEFAULTS = {f"V{i}": 0.0 for i in range(1, 29)}31 32 33def safe_groq_completion(messages, max_tokens=200, temperature=0.3):34    try:35        response = client.chat.completions.create(36            model="openai/gpt-oss-20b",37            messages=messages,38            max_tokens=max_tokens,39            temperature=temperature40        )41        return response.choices[0].message.content.strip(), None42 43    except Exception as e:44        err = str(e).lower()45 46        if "quota" in err or "rate limit" in err or "429" in err or "forbidden" in err:47            return None, "Groq quota exceeded. Please try again in a moment."48 49        return None, f"LLM error: {str(e)}"50 51 52def run_prediction(payload):53    try:54        response = requests.post(55            "https://fraud-api-kzt3.onrender.com/predict",56            json=payload,57            timeout=3058        )59        response.raise_for_status()60        result = response.json()61 62        if "is_fraud" not in result:63            st.error(f"API Error: {result}")64            return65 66        st.subheader("Prediction Result")67 68        if result["is_fraud"]:69            st.error("FRAUDULENT TRANSACTION DETECTED!")70        else:71            st.success("Legitimate Transaction")72 73        col1, col2, col3, col4 = st.columns(4)74        with col1:75            st.metric("Fraud", "YES" if result["is_fraud"] else "NO")76        with col2:77            st.metric("Probability", f"{result['fraud_probability']*100:.1f}%")78        with col3:79            st.metric("Risk Level", result["risk_level"])80        with col4:81            st.metric("Action", result.get("suggested_action", "N/A"))82 83        st.divider()84        st.markdown("### ๐Ÿค– Agent Pipeline")85        risk = result["risk_level"]86        action = result.get("suggested_action", "N/A")87        action_color = "๐Ÿ”ด" if risk == "HIGH" else "๐ŸŸก" if risk == "MEDIUM" else "๐ŸŸข"88        st.markdown(f"""89| Step | Output |90|------|--------|91| 1๏ธ Predict | Fraud: **{'YES' if result['is_fraud'] else 'NO'}** โ€” {result['fraud_probability']*100:.1f}% probability |92| 2๏ธ Risk Level | {action_color} **{risk}** |93| 3๏ธ Suggested Action | **{action}** |94""")95 96        similar = result.get("similar_cases", [])97        if similar:98            st.markdown(f"### Similar Past Fraud Cases ({len(similar)} found)")99            for i, c in enumerate(similar, 1):100                st.markdown(101                    f"**Case {i}** โ€” Amount: `${c['amount']}` | "102                    f"Probability: `{c['fraud_probability']*100:.1f}%` | "103                    f"Risk: `{c['risk_level']}` | "104                    f"Time: `{c['timestamp']}`"105                )106        else:107            st.markdown("### Similar Past Fraud Cases")108            st.caption("No similar past fraud cases found yet. Run more fraud predictions to build history.")109 110        if result["is_fraud"]:111            st.divider()112            st.markdown("### RAG Fraud Analysis")113 114            with st.spinner("Retrieving relevant fraud knowledge..."):115                query = (116                    f"V14={payload['V14']:.2f} V10={payload['V10']:.2f} "117                    f"V12={payload['V12']:.2f} amount={payload['Amount']} fraud detected"118                )119                retrieved_docs = rag_engine.retrieve(query, top_k=3)120 121            st.markdown("**Retrieved Knowledge Chunks**")122            for i, doc in enumerate(retrieved_docs, 1):123                with st.expander(f"{i}. [{doc['category']}] {doc['title']} โ€” relevance: {doc['score']:.3f}"):124                    st.write(doc["content"])125 126            with st.spinner("Generating grounded explanation..."):127                rag_prompt = rag_engine.build_rag_prompt(payload, result["fraud_probability"], retrieved_docs)128                rag_explanation, rag_error = safe_groq_completion(129                    messages=[{"role": "user", "content": rag_prompt}],130                    max_tokens=200131                )132 133            if rag_explanation:134                st.info(rag_explanation)135            else:136                st.warning(rag_error or "Explanation unavailable right now โ€” try again in a moment.")137 138            st.caption("Powered by RAG (sentence-transformers + FAISS cosine similarity) + GPT OSS 20B via Groq")139 140        elif result.get("explanation"):141            st.divider()142            st.markdown("### AI Fraud Analysis")143            st.info(result["explanation"])144            st.caption("Powered by GPT OSS 20B via Groq")145 146        st.session_state["last_result"] = result147        st.session_state["last_payload"] = payload148 149    except requests.exceptions.RequestException as e:150        st.error(f"API request failed: {e}")151    except Exception as e:152        st.error(f"Something went wrong: {e}")153 154 155tab1, tab2, tab3, tab4 = st.tabs(["Fraud Detector", "Natural Language", "AI Chat", "Knowledge Base"])156 157 158with tab1:159    st.markdown("Enter transaction details below to check if it's fraudulent.")160 161    if st.button("Load Sample Fraud Transaction", use_container_width=True):162        for key, val in sample_fraud.items():163            st.session_state[key] = val164 165    st.subheader("Transaction Details")166    col1, col2 = st.columns(2)167    with col1:168        Time = st.number_input("Time", value=st.session_state.get("Time", 0.0))169        Amount = st.number_input("Amount ($)", value=st.session_state.get("Amount", 0.0))170    with col2:171        st.markdown("**V1 โ€” V28** (PCA features)")172 173    st.markdown("**PCA Features (V1 - V28)**")174    cols = st.columns(4)175    v_values = {}176    for i in range(1, 29):177        col_idx = (i - 1) % 4178        with cols[col_idx]:179            v_values[f"V{i}"] = st.number_input(180                f"V{i}",181                value=st.session_state.get(f"V{i}", 0.0),182                format="%.4f"183            )184 185    st.divider()186 187    if st.button("Predict", use_container_width=True):188        payload = {"Time": Time, "Amount": Amount}189        payload.update(v_values)190        run_prediction(payload)191 192 193with tab2:194    st.markdown("### ๐Ÿ—ฃ๏ธ Describe a Transaction in Plain English")195    st.caption("Describe the transaction naturally โ€” the AI will extract features and run fraud detection.")196 197    st.markdown("""198**Try these examples:**199- `Transaction of $500 at 2AM from an unknown location`200- `Small $12 purchase at a local coffee shop during business hours`201- `$3000 international wire transfer at midnight on a new device`202- `Contactless $80 tap payment at grocery store at 6PM`203""")204 205    nl_input = st.text_area(206        "Describe the transaction",207        placeholder="e.g. Transaction of $500 at 2AM from an unknown location using a new device...",208        height=100209    )210 211    if st.button("Analyze Transaction", use_container_width=True):212        if not nl_input.strip():213            st.warning("Please describe a transaction first.")214        else:215            with st.spinner("Parsing transaction with AI..."):216                parse_prompt = f"""You are a credit card fraud detection feature extractor.217 218A user described a transaction in plain English. Extract structured features for a fraud detection model.219 220The model uses these key PCA features. Estimate values based on the transaction description:221- V14: Most important fraud signal. Normal: near 0. Suspicious: -2 to -5222- V10: Second most important. Suspicious: -2 to -4223- V12: Third most important. Suspicious: -2 to -4224- V17: Fourth. Suspicious: -2 to -3225- V4: High positive (2 to 4) = suspicious geographic anomaly226- All other V features: set to 0.0227 228Risk factors that push V14/V10/V12/V17 negative and V4 positive:229- Late night (12AM-4AM): high risk230- Unknown/foreign location: high risk231- Large amount (>$500): moderate risk232- New device or card: high risk233- International transaction: high risk234- Online/card-not-present: moderate risk235- Normal business hours + known location: low risk236- Small everyday purchase: low risk237 238Transaction: "{nl_input}"239 240Respond ONLY with valid JSON, no explanation:241{{242  "Amount": <number>,243  "Time": <seconds from midnight, e.g. 2AM = 7200>,244  "V4": <number>,245  "V10": <number>,246  "V12": <number>,247  "V14": <number>,248  "V17": <number>,249  "reasoning": "<one sentence explaining your risk assessment>"250}}"""251 252                raw, parse_error = safe_groq_completion(253                    messages=[{"role": "user", "content": parse_prompt}],254                    max_tokens=300255                )256 257            if not raw:258                st.error(parse_error or "Could not parse transaction right now.")259            else:260                try:261                    start = raw.find("{")262                    end = raw.rfind("}") + 1263                    parsed = json.loads(raw[start:end])264                    reasoning = parsed.pop("reasoning", "")265 266                    payload = {**V_DEFAULTS}267                    payload["Time"] = float(parsed.get("Time", 0))268                    payload["Amount"] = float(parsed.get("Amount", 0))269                    for key in ["V4", "V10", "V12", "V14", "V17"]:270                        if key in parsed:271                            payload[key] = float(parsed[key])272 273                    st.markdown("### Extracted Features")274                    c1, c2, c3 = st.columns(3)275                    with c1:276                        st.metric("Amount", f"${payload['Amount']:.2f}")277                    with c2:278                        h = int(payload['Time'] // 3600)279                        st.metric("Time", f"{h:02d}:00")280                    with c3:281                        st.metric("V14 (key signal)", f"{payload['V14']:.2f}")282 283                    c4, c5, c6 = st.columns(3)284                    with c4:285                        st.metric("V10", f"{payload['V10']:.2f}")286                    with c5:287                        st.metric("V12", f"{payload['V12']:.2f}")288                    with c6:289                        st.metric("V4", f"{payload['V4']:.2f}")290 291                    if reasoning:292                        st.info(f"**AI Reasoning:** {reasoning}")293 294                    st.divider()295                    run_prediction(payload)296 297                except Exception as e:298                    st.error(f"Failed to parse AI response: {e}")299                    st.code(raw)300 301 302with tab3:303    st.markdown("### Ask the AI about fraud detection")304    st.caption("Ask anything about the prediction, features, or fraud detection in general.")305 306    if "chat_history" not in st.session_state:307        st.session_state.chat_history = []308 309    system_prompt = """You are an expert AI assistant specializing in credit card fraud detection.310You help users understand fraud predictions made by an XGBoost machine learning model.311The dataset uses PCA-transformed features V1-V28 (anonymized for privacy), plus Time and Amount.312Key fraud indicators: V14, V10, V12, V17 (strongly negative = high fraud risk), V4 (high positive = suspicious).313Be concise, clear, and helpful. Explain technical concepts in simple terms."""314 315    if "last_result" in st.session_state:316        r = st.session_state["last_result"]317        p = st.session_state["last_payload"]318        system_prompt += f"""319 320Latest prediction context:321- Fraud detected: {r['is_fraud']}322- Probability: {r['fraud_probability']*100:.1f}%323- Risk level: {r['risk_level']}324- Suggested action: {r.get('suggested_action', 'N/A')}325- Amount: ${p['Amount']}326- Key features: V14={p['V14']:.4f}, V10={p['V10']:.4f}, V4={p['V4']:.4f}, V12={p['V12']:.4f}327- AI explanation: {r.get('explanation', 'N/A')}"""328 329    for msg in st.session_state.chat_history:330        with st.chat_message(msg["role"]):331            st.write(msg["content"])332 333    user_input = st.chat_input("Ask me anything about fraud detection...")334 335    if user_input:336        chat_docs = rag_engine.retrieve(user_input, top_k=2)337        rag_context = "\n\n".join([f"[{d['category']}] {d['title']}: {d['content']}" for d in chat_docs])338        enhanced_system = system_prompt + f"\n\nRelevant knowledge:\n{rag_context}"339 340        st.session_state.chat_history.append({"role": "user", "content": user_input})341        with st.chat_message("user"):342            st.write(user_input)343 344        with st.chat_message("assistant"):345            with st.spinner("Thinking..."):346                messages = [{"role": "system", "content": enhanced_system}]347                messages += st.session_state.chat_history348                reply, chat_error = safe_groq_completion(349                    messages=messages,350                    max_tokens=300351                )352 353                if reply:354                    st.write(reply)355                else:356                    reply = "AI chat is temporarily unavailable because the model quota was exceeded. Please try again shortly."357                    st.warning(reply)358 359        st.session_state.chat_history.append({"role": "assistant", "content": reply})360 361    if st.button("Clear Chat"):362        st.session_state.chat_history = []363        st.rerun()364 365 366with tab4:367    st.markdown("### Fraud Knowledge Base")368    st.caption(f"{len(rag_engine.documents)} documents across 6 categories")369 370    by_category = defaultdict(list)371    for doc in FRAUD_KNOWLEDGE_BASE:372        by_category[doc["category"]].append(doc)373 374    for category, docs in by_category.items():375        st.markdown(f"#### {category} ({len(docs)} docs)")376        for doc in docs:377            with st.expander(doc["title"]):378                st.write(doc["content"])379        st.divider()