File size: 10,709 Bytes
cffeaa1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GenAI Loan Advisor</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        .loader {
            border: 4px solid #f3f3f3;
            border-top: 4px solid #3b82f6;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            animation: spin 1s linear infinite;
            display: inline-block; 
        }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        pre { white-space: pre-wrap; word-wrap: break-word; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
        .data-box { max-height: 300px; overflow-y: auto; }
        #finalOutput { white-space: pre-wrap; line-height: 1.6; }
    </style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center py-10">

    <div class="w-full max-w-5xl bg-white shadow-xl rounded-xl p-8 border border-gray-200">
        <div class="border-b pb-4 mb-6 text-center">
            <h1 class="text-3xl font-extrabold text-gray-800 tracking-tight">GenAI Loan Advisor</h1>
            <p class="text-gray-500 mt-2 text-sm">Autonomous Multi-Agent System (CrewAI + Mistral)</p>
        </div>

        <div class="flex flex-col gap-4 mb-6">
            <div>
                <label class="block text-xs font-bold text-gray-500 uppercase mb-1">Access Code</label>
                <input type="password" id="accessCode" 
                    class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 shadow-sm text-gray-700 placeholder-gray-400"
                    placeholder="πŸ”‘ Enter the class code (Required)">
            </div>

            <div>
                <label class="block text-xs font-bold text-gray-500 uppercase mb-1">Your Question</label>
                <div class="flex gap-2">
                    <input type="text" id="userQuery" 
                        class="w-full p-4 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 shadow-sm text-gray-700"
                        placeholder="e.g., What is the rate for Andy?">
                    <button onclick="sendQuery()" id="submitBtn"
                        class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-8 rounded-lg transition duration-200 shadow-md whitespace-nowrap disabled:bg-gray-400 disabled:cursor-not-allowed">
                        Analyze
                    </button>
                </div>
            </div>
        </div>
        
        <p class="text-xs text-gray-400 text-center mb-6">Try Asking What is the recommended rate for Hilda?  What is consider high risk? Or just say Hello</p>

        <div id="loadingState" class="hidden mt-8 text-center">
            <div class="loader mb-3"></div>
            <p class="text-gray-500 text-sm font-medium animate-pulse">
                πŸš€ Agents are coordinating... this may take up to 45 seconds.
            </p>
            <p class="text-xs text-gray-400 mt-1">(Gathering data, checking policies, and underwriting)</p>
        </div>

        <div id="resultsArea" class="hidden mt-8 space-y-6 animate-fade-in">
            <div class="bg-gradient-to-r from-green-50 to-white border-l-4 border-green-500 p-6 rounded shadow-sm">
                <h3 class="text-lg font-bold text-green-800 flex items-center gap-2">βœ… Final Decision</h3>
                <div id="finalOutput" class="text-gray-800 mt-3 text-base leading-relaxed"></div>
            </div>

            <div class="bg-blue-50 border-l-4 border-blue-500 p-5 rounded shadow-sm">
                <h3 class="text-sm font-bold text-blue-800 uppercase tracking-wide mb-3 flex items-center gap-2">🧠 Supervisor Strategy</h3>
                <div id="planOutput" class="text-sm text-gray-700"></div>
            </div>

            <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                <div class="bg-gray-50 border border-gray-200 p-5 rounded shadow-sm h-full">
                    <h3 class="text-xs font-bold text-gray-500 uppercase mb-3 flex items-center gap-2">πŸ‘€ Customer Profile</h3>
                    <div id="customerOutput" class="data-box text-sm text-gray-700"></div>
                </div>
                <div class="bg-gray-50 border border-gray-200 p-5 rounded shadow-sm h-full">
                    <h3 class="text-xs font-bold text-gray-500 uppercase mb-3 flex items-center gap-2">πŸ“œ Policy Context (RAG)</h3>
                    <div id="policyOutput" class="data-box text-xs text-gray-600 bg-white p-3 rounded border border-gray-100 italic"></div>
                </div>
            </div>
        </div>
    </div>

<script>
    async function sendQuery() {
        const queryInput = document.getElementById('userQuery');
        const codeInput = document.getElementById('accessCode');
        const resultsArea = document.getElementById('resultsArea');
        const loadingState = document.getElementById('loadingState'); // Target the new container
        const submitBtn = document.getElementById('submitBtn'); // Target button to disable it
        
        const query = queryInput.value.trim();
        const code = codeInput.value.trim();

        if (!code || !query) return alert("Please fill in both fields.");

        // UI Updates: Hide results, Show Loader, Disable Button
        resultsArea.classList.add('hidden');
        loadingState.classList.remove('hidden');
        submitBtn.disabled = true;
        submitBtn.innerText = "Processing...";

        try {
            const response = await fetch('/ask', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ query, code })
            });

            const result = await response.json();
            
            if (result.status === 'success') {
                const data = result.data;

                // 1. FINAL RESOLUTION
                let recText = data.final_recommendation || "System could not provide a resolution.";
                recText = recText.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
                document.getElementById('finalOutput').innerHTML = recText;

                // 2. STRATEGY
                const planObj = data.plan || {};
                const planHtml = `
                    <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                        <div class="col-span-1 md:col-span-2"><span class="font-semibold text-blue-900">Thought:</span> <span class="italic text-gray-600">${planObj.thought_process || "Processing query..."}</span></div>
                        <div><span class="font-semibold text-gray-700">Intent:</span> ${planObj.intent || "Unknown"}</div>
                        <div><span class="font-semibold text-gray-700">Detected Name:</span> ${planObj.customer_name || "None"}</div>
                        <div><span class="font-semibold text-gray-700">DB Check:</span> <span class="${planObj.requires_database ? 'text-green-600 font-bold' : 'text-gray-400'}">${planObj.requires_database ? "YES" : "NO"}</span></div>
                        <div><span class="font-semibold text-gray-700">Policy Check:</span> <span class="${planObj.requires_policy ? 'text-green-600 font-bold' : 'text-gray-400'}">${planObj.requires_policy ? "YES" : "NO"}</span></div>
                    </div>`;
                document.getElementById('planOutput').innerHTML = planHtml;

                // 3. CUSTOMER DATA
                let customerHtml = "";
                try {
                    let custData = data.customer_data;
                    
                    if (typeof custData === 'string') {
                        if (custData.includes("NOT_FOUND") || custData.includes("N/A")) {
                             customerHtml = `<div class="bg-red-50 text-red-700 p-3 rounded font-bold text-center">❌ No Record Found</div>`;
                        } else {
                            customerHtml = `<div class="text-gray-600 text-xs italic">${custData}</div>`;
                        }
                    } 
                    else if (typeof custData === 'object' && custData !== null) {
                        customerHtml = `<div class="grid grid-cols-2 gap-y-2 gap-x-4">`;
                        for (const [key, value] of Object.entries(custData)) {
                            let label = key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
                            
                            let valDisplay = value;
                            if (value === false) valDisplay = '<span class="text-red-500 font-bold">False</span>';
                            if (value === true) valDisplay = '<span class="text-green-600 font-bold">True</span>';
                            if (key === 'credit_score' && typeof value === 'number') {
                                valDisplay = value >= 700 
                                    ? `<span class="text-green-600 font-bold">${value}</span>` 
                                    : `<span class="text-amber-600 font-bold">${value}</span>`;
                            }
                            
                            customerHtml += `<div class="text-gray-400 text-[10px] uppercase pt-1">${label}</div><div class="font-medium text-gray-800 break-words">${valDisplay}</div>`;
                        }
                        customerHtml += `</div>`;
                    }
                } catch (e) {
                    console.error("Rendering Error:", e);
                    customerHtml = `<div class="text-gray-600 text-xs italic">Error loading data.</div>`;
                }
                document.getElementById('customerOutput').innerHTML = customerHtml;

                // 4. POLICY CONTEXT
                document.getElementById('policyOutput').textContent = data.policy_data || "No relevant policy snippets retrieved.";
                
                resultsArea.classList.remove('hidden');

            } else {
                alert(result.message || "Access Denied.");
            }

        } catch (error) {
            console.error(error);
            alert("Server connection failed.");
        } finally {
            // Restore UI state
            loadingState.classList.add('hidden');
            submitBtn.disabled = false;
            submitBtn.innerText = "Analyze";
        }
    }

    document.getElementById("userQuery").addEventListener("keypress", function(event) {
        if (event.key === "Enter") sendQuery();
    });
</script>
</body>
</html>