Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -1400,7 +1400,7 @@ def show_signup():
|
|
1400 |
]
|
1401 |
|
1402 |
def return_to_landing():
|
1403 |
-
"""Return to landing page"""
|
1404 |
return [
|
1405 |
gr.update(visible=True), # landing_page
|
1406 |
gr.update(visible=False), # signin_page
|
@@ -1481,7 +1481,7 @@ def show_dashboard(phone, name):
|
|
1481 |
gr.update(visible=False), # signin_page
|
1482 |
gr.update(visible=False), # signup_page
|
1483 |
gr.update(visible=True), # dashboard_page
|
1484 |
-
f"Welcome back, {name}
|
1485 |
f"<div class='balance-amount'>π° {format_currency(current_balance)}</div>", # balance display
|
1486 |
phone, # current_user state
|
1487 |
monthly_income, # income
|
@@ -1504,7 +1504,7 @@ def show_dashboard(phone, name):
|
|
1504 |
return [
|
1505 |
gr.update(visible=False), gr.update(visible=False),
|
1506 |
gr.update(visible=False), gr.update(visible=True),
|
1507 |
-
f"Welcome, {name}
|
1508 |
"<div class='balance-amount'>π° 0 PKR</div>",
|
1509 |
phone, 0, 0, *empty_alloc, [], [], [], None, None,
|
1510 |
"No family group", [], []
|
@@ -2066,216 +2066,522 @@ def handle_receipt_save(current_user, receipt_data, merchant, amount, date, cate
|
|
2066 |
current_balance = db.get_current_balance(current_user) if current_user else 0
|
2067 |
return f"β Error saving receipt: {str(e)}", f"<div class='balance-amount'>π° {format_currency(current_balance)}</div>", [], []
|
2068 |
|
2069 |
-
# ========== I) CUSTOM CSS ==========
|
2070 |
custom_css = """
|
2071 |
-
/* Enhanced CSS for better UI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2072 |
.gradio-container {
|
2073 |
-
max-width:
|
2074 |
margin: 0 auto !important;
|
2075 |
-
|
|
|
|
|
|
|
2076 |
}
|
2077 |
|
|
|
2078 |
.landing-hero {
|
2079 |
-
background: linear-gradient(135deg,
|
2080 |
-
min-height:
|
2081 |
-
padding:
|
2082 |
color: white;
|
2083 |
text-align: center;
|
2084 |
-
border-radius:
|
2085 |
-
margin:
|
2086 |
-
box-shadow:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2087 |
}
|
2088 |
|
2089 |
.hero-title {
|
2090 |
-
font-size:
|
2091 |
-
font-weight:
|
2092 |
-
margin-bottom:
|
2093 |
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
|
|
|
|
|
|
|
|
|
|
|
|
|
2094 |
}
|
2095 |
|
2096 |
.hero-subtitle {
|
2097 |
-
font-size: 1.
|
2098 |
-
margin-bottom:
|
2099 |
-
opacity: 0.
|
|
|
|
|
|
|
|
|
2100 |
}
|
2101 |
|
2102 |
.features-grid {
|
2103 |
display: grid;
|
2104 |
-
grid-template-columns: repeat(auto-fit, minmax(
|
2105 |
gap: 2rem;
|
2106 |
margin: 3rem 0;
|
|
|
|
|
2107 |
}
|
2108 |
|
2109 |
.feature-card {
|
2110 |
-
background: rgba(255,255,255,0.
|
2111 |
-
backdrop-filter: blur(
|
2112 |
-
border-radius:
|
2113 |
-
padding: 2rem;
|
2114 |
text-align: center;
|
2115 |
border: 1px solid rgba(255,255,255,0.2);
|
2116 |
-
transition:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2117 |
}
|
2118 |
|
2119 |
.feature-card:hover {
|
2120 |
-
transform: translateY(-
|
2121 |
-
box-shadow: 0
|
|
|
2122 |
}
|
2123 |
|
2124 |
.feature-icon {
|
2125 |
-
font-size:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2126 |
margin-bottom: 1rem;
|
|
|
2127 |
}
|
2128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2129 |
.auth-container {
|
2130 |
-
max-width:
|
2131 |
margin: 2rem auto;
|
2132 |
-
background:
|
2133 |
-
border-radius:
|
2134 |
-
padding: 3rem;
|
2135 |
-
box-shadow:
|
2136 |
-
border: 1px solid
|
|
|
|
|
2137 |
}
|
2138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2139 |
.whatsapp-setup {
|
2140 |
background: linear-gradient(135deg, #25D366 0%, #128C7E 100%);
|
2141 |
color: white;
|
2142 |
-
padding:
|
2143 |
-
border-radius:
|
2144 |
margin: 2rem 0;
|
2145 |
text-align: center;
|
2146 |
-
box-shadow: 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2147 |
}
|
2148 |
|
2149 |
.whatsapp-steps {
|
2150 |
-
background: rgba(255, 255, 255, 0.
|
2151 |
-
backdrop-filter: blur(
|
2152 |
-
border-radius:
|
2153 |
-
padding:
|
2154 |
-
margin:
|
2155 |
border: 1px solid rgba(255, 255, 255, 0.2);
|
2156 |
text-align: left;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2157 |
}
|
2158 |
|
2159 |
-
.phone-highlight {
|
2160 |
-
background: rgba(255, 255, 255, 0.
|
2161 |
-
padding: 0.
|
2162 |
-
border-radius:
|
2163 |
-
font-family: 'Monaco', '
|
2164 |
font-size: 1.1rem;
|
2165 |
font-weight: bold;
|
2166 |
display: inline-block;
|
2167 |
-
margin: 0.
|
|
|
|
|
2168 |
}
|
2169 |
|
2170 |
.code-highlight {
|
2171 |
-
|
2172 |
-
padding: 0.5rem 1rem;
|
2173 |
-
border-radius: 8px;
|
2174 |
-
font-family: 'Monaco', 'Menlo', monospace;
|
2175 |
-
font-size: 1rem;
|
2176 |
-
font-weight: bold;
|
2177 |
-
display: inline-block;
|
2178 |
-
margin: 0.5rem 0;
|
2179 |
-
border-left: 3px solid #fff;
|
2180 |
}
|
2181 |
|
|
|
2182 |
.dashboard-header {
|
2183 |
-
background: linear-gradient(135deg,
|
2184 |
color: white;
|
2185 |
-
padding:
|
2186 |
-
border-radius:
|
2187 |
margin-bottom: 2rem;
|
2188 |
text-align: center;
|
2189 |
-
font-size: 1.
|
2190 |
-
box-shadow:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2191 |
}
|
2192 |
|
2193 |
.balance-card {
|
2194 |
-
background: linear-gradient(135deg,
|
2195 |
color: white;
|
2196 |
-
padding:
|
2197 |
-
border-radius:
|
2198 |
text-align: center;
|
2199 |
margin-bottom: 2rem;
|
2200 |
-
box-shadow:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2201 |
}
|
2202 |
|
2203 |
.balance-amount {
|
2204 |
-
font-size:
|
2205 |
-
font-weight:
|
2206 |
-
margin:
|
2207 |
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
|
|
|
|
|
|
|
|
2208 |
}
|
2209 |
|
2210 |
-
|
2211 |
-
|
2212 |
border: none !important;
|
2213 |
border-radius: 25px !important;
|
2214 |
padding: 1rem 2rem !important;
|
2215 |
font-size: 1.1rem !important;
|
2216 |
font-weight: 600 !important;
|
2217 |
color: white !important;
|
2218 |
-
transition:
|
2219 |
-
box-shadow: 0 4px 15px rgba(238, 90, 36, 0.4) !important;
|
2220 |
cursor: pointer !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2221 |
}
|
2222 |
|
2223 |
.primary-btn:hover {
|
2224 |
-
transform: translateY(-
|
2225 |
-
box-shadow: 0
|
2226 |
}
|
2227 |
|
2228 |
.secondary-btn {
|
2229 |
background: linear-gradient(45deg, #74b9ff, #0984e3) !important;
|
2230 |
-
border: none !important;
|
2231 |
-
border-radius: 25px !important;
|
2232 |
-
padding: 1rem 2rem !important;
|
2233 |
-
font-size: 1.1rem !important;
|
2234 |
-
font-weight: 600 !important;
|
2235 |
-
color: white !important;
|
2236 |
-
transition: all 0.3s ease !important;
|
2237 |
box-shadow: 0 4px 15px rgba(116, 185, 255, 0.4) !important;
|
2238 |
-
cursor: pointer !important;
|
2239 |
}
|
2240 |
|
2241 |
.secondary-btn:hover {
|
2242 |
-
transform: translateY(-
|
2243 |
-
box-shadow: 0
|
2244 |
}
|
2245 |
|
2246 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2247 |
.dataframe {
|
2248 |
-
border-radius:
|
2249 |
overflow: hidden !important;
|
2250 |
-
box-shadow:
|
2251 |
-
border: 1px solid
|
|
|
|
|
2252 |
}
|
2253 |
|
2254 |
.dataframe th {
|
2255 |
-
background: linear-gradient(135deg,
|
2256 |
font-weight: 600 !important;
|
2257 |
-
padding: 1rem !important;
|
2258 |
-
border-bottom: 2px solid
|
|
|
|
|
|
|
|
|
2259 |
}
|
2260 |
|
2261 |
.dataframe td {
|
2262 |
-
padding:
|
2263 |
border-bottom: 1px solid #f1f5f9 !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2264 |
}
|
2265 |
|
2266 |
-
/* Status
|
2267 |
.status-success {
|
2268 |
-
color:
|
|
|
|
|
|
|
|
|
2269 |
font-weight: 600 !important;
|
|
|
2270 |
}
|
2271 |
|
2272 |
.status-error {
|
2273 |
-
color:
|
|
|
|
|
|
|
|
|
2274 |
font-weight: 600 !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2275 |
}
|
2276 |
|
2277 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2278 |
@media (max-width: 768px) {
|
|
|
|
|
|
|
|
|
2279 |
.hero-title {
|
2280 |
font-size: 2.5rem;
|
2281 |
}
|
@@ -2286,33 +2592,203 @@ custom_css = """
|
|
2286 |
|
2287 |
.features-grid {
|
2288 |
grid-template-columns: 1fr;
|
2289 |
-
gap:
|
2290 |
}
|
2291 |
|
2292 |
.auth-container {
|
2293 |
margin: 1rem;
|
2294 |
-
padding: 2rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2295 |
}
|
2296 |
|
2297 |
.balance-amount {
|
2298 |
font-size: 2rem;
|
2299 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2300 |
}
|
2301 |
|
2302 |
-
/* Loading
|
2303 |
.loading {
|
2304 |
opacity: 0.6;
|
2305 |
pointer-events: none;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2306 |
}
|
2307 |
|
2308 |
/* Animations */
|
2309 |
@keyframes fadeIn {
|
2310 |
-
from {
|
2311 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2312 |
}
|
2313 |
|
2314 |
.fade-in {
|
2315 |
-
animation: fadeIn 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2316 |
}
|
2317 |
"""
|
2318 |
|
@@ -2323,7 +2799,7 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2323 |
receipt_data = gr.State({})
|
2324 |
|
2325 |
# ===== LANDING PAGE =====
|
2326 |
-
with gr.Column(visible=True) as landing_page:
|
2327 |
gr.HTML("""
|
2328 |
<div class="landing-hero">
|
2329 |
<div class="hero-title">π¦ FinGenius Pro</div>
|
@@ -2333,52 +2809,52 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2333 |
<div class="feature-card">
|
2334 |
<div class="feature-icon">π°</div>
|
2335 |
<h3>Smart Balance Tracking</h3>
|
2336 |
-
<p>Real-time balance monitoring with intelligent spending alerts</p>
|
2337 |
</div>
|
2338 |
<div class="feature-card">
|
2339 |
<div class="feature-icon">π±</div>
|
2340 |
<h3>WhatsApp Integration</h3>
|
2341 |
-
<p>Get instant notifications for every expense and
|
2342 |
</div>
|
2343 |
<div class="feature-card">
|
2344 |
<div class="feature-icon">π</div>
|
2345 |
<h3>Advanced Analytics</h3>
|
2346 |
-
<p>Beautiful charts and insights to track
|
2347 |
</div>
|
2348 |
<div class="feature-card">
|
2349 |
<div class="feature-icon">π§Ύ</div>
|
2350 |
-
<h3>Receipt Scanning</h3>
|
2351 |
-
<p>
|
2352 |
</div>
|
2353 |
<div class="feature-card">
|
2354 |
<div class="feature-icon">πͺ</div>
|
2355 |
-
<h3>Family Finance</h3>
|
2356 |
-
<p>Create family groups to manage household finances
|
2357 |
</div>
|
2358 |
<div class="feature-card">
|
2359 |
<div class="feature-icon">π</div>
|
2360 |
-
<h3>
|
2361 |
-
<p>
|
2362 |
</div>
|
2363 |
</div>
|
2364 |
</div>
|
2365 |
""")
|
2366 |
|
2367 |
-
with gr.Row():
|
2368 |
with gr.Column(scale=1):
|
2369 |
signin_btn = gr.Button("π Sign In", variant="primary", elem_classes="primary-btn", size="lg")
|
2370 |
with gr.Column(scale=1):
|
2371 |
signup_btn = gr.Button("β¨ Create Account", variant="secondary", elem_classes="secondary-btn", size="lg")
|
2372 |
|
2373 |
# ===== SIGN IN PAGE =====
|
2374 |
-
with gr.Column(visible=False) as signin_page:
|
2375 |
with gr.Column(elem_classes="auth-container"):
|
2376 |
-
gr.HTML("<h2 style='text-align: center; color: #2d3748; margin-bottom: 2rem;'>π Welcome Back</h2>")
|
2377 |
|
2378 |
signin_phone = gr.Textbox(
|
2379 |
label="π± WhatsApp Number",
|
2380 |
placeholder="+92XXXXXXXXXX",
|
2381 |
-
info="Enter your registered WhatsApp number"
|
2382 |
)
|
2383 |
signin_password = gr.Textbox(
|
2384 |
label="π Password",
|
@@ -2386,16 +2862,16 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2386 |
placeholder="Enter your secure password"
|
2387 |
)
|
2388 |
|
2389 |
-
with gr.Row():
|
2390 |
-
submit_signin = gr.Button("Sign In", variant="primary", elem_classes="primary-btn", scale=
|
2391 |
-
back_to_landing_1 = gr.Button("β Back", variant="secondary", scale=1)
|
2392 |
|
2393 |
-
signin_status = gr.Textbox(label="Status", interactive=False)
|
2394 |
|
2395 |
# ===== SIGN UP PAGE =====
|
2396 |
-
with gr.Column(visible=False) as signup_page:
|
2397 |
with gr.Column(elem_classes="auth-container"):
|
2398 |
-
gr.HTML("<h2 style='text-align: center; color: #2d3748; margin-bottom: 2rem;'>β¨ Create Your Account</h2>")
|
2399 |
|
2400 |
signup_name = gr.Textbox(
|
2401 |
label="π€ Full Name",
|
@@ -2404,7 +2880,7 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2404 |
signup_phone = gr.Textbox(
|
2405 |
label="π± WhatsApp Number",
|
2406 |
placeholder="+92XXXXXXXXXX",
|
2407 |
-
info="This will be used for notifications"
|
2408 |
)
|
2409 |
signup_password = gr.Textbox(
|
2410 |
label="π Create Password",
|
@@ -2417,16 +2893,17 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2417 |
placeholder="Re-enter your password"
|
2418 |
)
|
2419 |
|
2420 |
-
# WhatsApp Setup Instructions
|
2421 |
gr.HTML("""
|
2422 |
<div class='whatsapp-setup'>
|
2423 |
-
<h3>π± Enable WhatsApp Alerts</h3>
|
2424 |
-
<p style='font-size: 1.
|
2425 |
|
2426 |
<div class='whatsapp-steps'>
|
2427 |
<h4>Step 1: Save the Bot Number</h4>
|
2428 |
<p>Add this Twilio WhatsApp Sandbox number to your contacts:</p>
|
2429 |
<div class='phone-highlight'>+1 (415) 523-8886</div>
|
|
|
2430 |
</div>
|
2431 |
|
2432 |
<div class='whatsapp-steps'>
|
@@ -2434,156 +2911,286 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2434 |
<p>Send this exact message to the number above:</p>
|
2435 |
<div class='code-highlight'>join catch-manner</div>
|
2436 |
<p style='font-size: 0.9rem; opacity: 0.8; margin-top: 0.5rem;'>
|
2437 |
-
β οΈ <strong>
|
2438 |
</p>
|
2439 |
</div>
|
2440 |
|
2441 |
<div class='whatsapp-steps'>
|
2442 |
<h4>Step 3: Confirm Registration</h4>
|
2443 |
<p>After sending the code, register your FinGenius account with the <strong>same phone number</strong> you used to message the bot.</p>
|
|
|
2444 |
</div>
|
2445 |
|
2446 |
<div class='whatsapp-steps'>
|
2447 |
-
<h4>Step 4: Start Receiving Alerts</h4>
|
2448 |
<p>You'll receive instant WhatsApp notifications for:</p>
|
2449 |
-
<ul style='text-align: left; margin-left:
|
2450 |
<li>β
Account registration confirmation</li>
|
2451 |
-
<li>π° Balance updates</li>
|
2452 |
-
<li>πΈ
|
2453 |
<li>π§Ύ Receipt processing confirmations</li>
|
2454 |
-
<li>π Investment tracking</li>
|
2455 |
-
<li>π¨ Budget alerts</li>
|
|
|
|
|
2456 |
</ul>
|
2457 |
</div>
|
2458 |
</div>
|
2459 |
""")
|
2460 |
|
2461 |
-
with gr.Row():
|
2462 |
-
submit_signup = gr.Button("Complete Registration", variant="primary", elem_classes="primary-btn", scale=
|
2463 |
-
back_to_landing_2 = gr.Button("β Back", variant="secondary", scale=1)
|
2464 |
|
2465 |
-
signup_status = gr.Textbox(label="Status", interactive=False)
|
2466 |
|
2467 |
# ===== DASHBOARD PAGE =====
|
2468 |
-
with gr.Column(visible=False) as dashboard_page:
|
2469 |
-
# Dashboard Header
|
2470 |
welcome_message = gr.HTML("", elem_classes="dashboard-header")
|
2471 |
|
2472 |
-
# Current Balance Display
|
2473 |
with gr.Column(elem_classes="balance-card"):
|
2474 |
balance_display = gr.HTML("<div class='balance-amount'>π° 0 PKR</div>")
|
2475 |
|
2476 |
with gr.Row():
|
2477 |
with gr.Column(scale=2):
|
2478 |
-
balance_amount = gr.Number(
|
2479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2480 |
with gr.Column(scale=1):
|
2481 |
-
add_balance_btn = gr.Button("Add Balance", variant="primary", elem_classes="primary-btn")
|
2482 |
|
2483 |
-
balance_status = gr.Textbox(label="Balance Status", interactive=False)
|
2484 |
|
2485 |
with gr.Tabs(elem_classes="tab-nav"):
|
2486 |
-
# Dashboard Overview Tab
|
2487 |
with gr.Tab("π Dashboard Overview"):
|
2488 |
gr.HTML("""
|
2489 |
-
<div style="text-align: center; padding: 3rem;
|
2490 |
-
<h2>π Welcome to FinGenius Pro!</h2>
|
2491 |
-
<p style="font-size: 1.
|
2492 |
</div>
|
2493 |
""")
|
2494 |
|
2495 |
with gr.Row():
|
2496 |
-
gr.
|
2497 |
-
|
2498 |
-
<
|
2499 |
-
|
2500 |
-
<
|
2501 |
-
|
2502 |
-
|
2503 |
-
|
2504 |
-
|
2505 |
-
|
2506 |
-
|
2507 |
-
|
2508 |
-
|
2509 |
-
|
2510 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2511 |
with gr.Tab("π₯ Income & Goals"):
|
2512 |
-
gr.HTML("
|
|
|
|
|
|
|
|
|
|
|
2513 |
|
2514 |
with gr.Row():
|
2515 |
-
|
2516 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2517 |
|
2518 |
-
|
2519 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2520 |
|
2521 |
-
# Budget Planner Tab
|
2522 |
with gr.Tab("π Budget Planner"):
|
2523 |
-
gr.HTML("
|
|
|
|
|
|
|
|
|
|
|
2524 |
|
2525 |
with gr.Column():
|
2526 |
allocation_inputs = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2527 |
with gr.Row():
|
2528 |
-
for
|
2529 |
-
alloc = gr.Number(
|
|
|
|
|
|
|
|
|
|
|
|
|
2530 |
allocation_inputs.append(alloc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2531 |
with gr.Row():
|
2532 |
-
for
|
2533 |
-
alloc = gr.Number(
|
|
|
|
|
|
|
|
|
|
|
|
|
2534 |
allocation_inputs.append(alloc)
|
2535 |
|
2536 |
allocate_btn = gr.Button("πΎ Save Budget Allocations", variant="primary", elem_classes="primary-btn", size="lg")
|
2537 |
-
allocation_status = gr.Textbox(label="Status", interactive=False)
|
2538 |
|
2539 |
-
gr.HTML("<h4>π Current Budget
|
2540 |
expense_table = gr.Dataframe(
|
2541 |
-
headers=["Category", "Allocated", "Spent", "Remaining", "
|
2542 |
interactive=False,
|
2543 |
-
wrap=True
|
|
|
2544 |
)
|
2545 |
|
2546 |
-
# Receipt Scan Tab
|
2547 |
with gr.Tab("π· Receipt Scan"):
|
2548 |
gr.HTML("""
|
2549 |
-
<div
|
2550 |
-
<h2>π§Ύ AI-Powered Receipt Scanner</h2>
|
2551 |
-
<p style="font-size: 1.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2552 |
</div>
|
2553 |
""")
|
2554 |
|
2555 |
with gr.Row():
|
2556 |
with gr.Column(scale=1):
|
2557 |
-
gr.HTML("<h4>π€ Upload Receipt</h4>")
|
2558 |
|
2559 |
receipt_image = gr.File(
|
2560 |
label="π· Receipt Image",
|
2561 |
-
file_types=["image/jpeg", "image/jpg", "image/png", "image/bmp", "image/tiff", "image/webp"]
|
|
|
2562 |
)
|
2563 |
|
2564 |
process_receipt_btn = gr.Button(
|
2565 |
-
"π Process Receipt",
|
2566 |
variant="primary",
|
2567 |
elem_classes="primary-btn",
|
2568 |
size="lg"
|
2569 |
)
|
2570 |
|
2571 |
-
receipt_status = gr.Textbox(label="Processing Status", interactive=False)
|
2572 |
|
2573 |
-
# Image Preview
|
2574 |
-
gr.HTML("<h4>πΈ Receipt Preview</h4>")
|
2575 |
receipt_preview = gr.Image(
|
2576 |
label="Receipt Preview",
|
2577 |
-
type="filepath"
|
|
|
2578 |
)
|
2579 |
|
2580 |
with gr.Column(scale=1):
|
2581 |
-
gr.HTML("<h4>βοΈ Verify & Edit Extracted Data</h4>")
|
2582 |
|
2583 |
extracted_merchant = gr.Textbox(
|
2584 |
label="πͺ Merchant Name",
|
2585 |
placeholder="Store/Restaurant name",
|
2586 |
-
info="
|
2587 |
)
|
2588 |
|
2589 |
with gr.Row():
|
@@ -2591,129 +3198,324 @@ with gr.Blocks(title="FinGenius Pro", theme=gr.themes.Soft(), css=custom_css) as
|
|
2591 |
label="π° Total Amount (PKR)",
|
2592 |
minimum=0,
|
2593 |
step=0.01,
|
2594 |
-
value=0
|
|
|
2595 |
)
|
2596 |
extracted_date = gr.Textbox(
|
2597 |
-
label="
|
2598 |
-
placeholder="YYYY-MM-DD or DD/MM/YYYY"
|
|
|
2599 |
)
|
2600 |
|
2601 |
extracted_category = gr.Dropdown(
|
2602 |
choices=EXPENSE_CATEGORIES,
|
2603 |
-
label="π·οΈ Category",
|
2604 |
value="Miscellaneous",
|
2605 |
info="AI-suggested category (you can change it)"
|
2606 |
)
|
2607 |
|
2608 |
-
gr.HTML("<h4>π
|
2609 |
line_items_table = gr.Dataframe(
|
2610 |
-
headers=["Item", "Price"],
|
2611 |
datatype=["str", "number"],
|
2612 |
row_count=5,
|
2613 |
col_count=2,
|
2614 |
interactive=True,
|
2615 |
-
label="
|
|
|
2616 |
)
|
2617 |
|
2618 |
save_receipt_btn = gr.Button(
|
2619 |
-
"πΎ Save as Expense",
|
2620 |
variant="primary",
|
2621 |
elem_classes="primary-btn",
|
2622 |
size="lg"
|
2623 |
)
|
2624 |
|
2625 |
-
# Receipt History
|
2626 |
-
gr.HTML("<h4>π§Ύ Recent
|
2627 |
receipts_table = gr.Dataframe(
|
2628 |
-
headers=["Receipt ID", "Merchant", "Amount", "Date", "Category", "Confidence", "Status", "Processed"],
|
2629 |
interactive=False,
|
2630 |
-
wrap=True
|
|
|
2631 |
)
|
2632 |
|
2633 |
-
# Expense Tracker Tab
|
2634 |
with gr.Tab("πΈ Expense Tracker"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2635 |
with gr.Row():
|
2636 |
-
with gr.Column():
|
2637 |
-
gr.HTML("<h4>β
|
2638 |
-
|
2639 |
-
|
2640 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2641 |
|
2642 |
with gr.Accordion("π Recurring Expense Settings", open=False):
|
2643 |
-
is_recurring = gr.Checkbox(
|
2644 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2645 |
|
2646 |
-
record_expense_btn = gr.Button(
|
2647 |
-
|
|
|
|
|
|
|
|
|
|
|
2648 |
|
2649 |
-
with gr.Column():
|
2650 |
-
gr.HTML("<h4>π
|
2651 |
-
|
2652 |
-
|
2653 |
-
|
2654 |
-
|
2655 |
-
|
2656 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2657 |
|
2658 |
-
# Spending History Tab
|
2659 |
with gr.Tab("π Spending History"):
|
2660 |
-
gr.HTML("
|
|
|
|
|
|
|
|
|
|
|
|
|
2661 |
spending_log_table = gr.Dataframe(
|
2662 |
-
headers=["Category", "Amount", "Description", "Date", "Balance After"],
|
2663 |
interactive=False,
|
2664 |
-
wrap=True
|
|
|
2665 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2666 |
|
2667 |
-
# Investment Portfolio Tab
|
2668 |
with gr.Tab("π Investment Portfolio"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2669 |
with gr.Row():
|
2670 |
-
with gr.Column():
|
2671 |
-
gr.HTML("<h4>β Add New Investment</h4>")
|
2672 |
-
|
2673 |
-
|
2674 |
-
|
2675 |
-
|
2676 |
-
|
2677 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2678 |
|
2679 |
-
with gr.Column():
|
2680 |
-
gr.HTML("<h4>πΌ Your Investment Portfolio</h4>")
|
|
|
2681 |
investments_table = gr.Dataframe(
|
2682 |
-
headers=["Type", "Name", "Amount", "Date", "Notes"],
|
2683 |
interactive=False,
|
2684 |
-
wrap=True
|
|
|
2685 |
)
|
2686 |
-
|
2687 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2688 |
with gr.Tab("πͺ Family Finance"):
|
2689 |
-
gr.HTML("
|
2690 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2691 |
|
2692 |
with gr.Row():
|
2693 |
-
with gr.Column():
|
2694 |
-
gr.HTML("<h4>β Create New Family Group</h4>")
|
2695 |
-
|
2696 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2697 |
|
2698 |
-
with gr.Column():
|
2699 |
-
gr.HTML("<h4>π Join Existing Group</h4>")
|
2700 |
-
|
2701 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2702 |
|
2703 |
-
family_status = gr.Textbox(label="Status", interactive=False)
|
2704 |
|
2705 |
-
gr.HTML("<h4>π₯ Family Members</h4>")
|
2706 |
family_members = gr.Dataframe(
|
2707 |
-
headers=["Phone", "Name"],
|
2708 |
interactive=False,
|
2709 |
-
wrap=True
|
|
|
2710 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2711 |
|
|
|
2712 |
with gr.Row():
|
2713 |
-
with gr.Column(scale=
|
2714 |
-
|
2715 |
with gr.Column(scale=1):
|
2716 |
-
sign_out_btn = gr.Button(
|
|
|
|
|
|
|
|
|
|
|
2717 |
|
2718 |
# ===== EVENT HANDLERS =====
|
2719 |
|
@@ -2841,17 +3643,30 @@ if __name__ == "__main__":
|
|
2841 |
logger.info(" 4. Use the same phone number for both WhatsApp activation and app registration")
|
2842 |
logger.info(" 5. Phone number format: +92XXXXXXXXXX (Pakistan format)")
|
2843 |
logger.info("")
|
2844 |
-
logger.info("β
All
|
2845 |
-
logger.info(" β
Fixed
|
2846 |
-
logger.info(" β
|
2847 |
-
logger.info(" β
Enhanced
|
2848 |
-
logger.info(" β
|
2849 |
-
logger.info(" β
|
2850 |
-
logger.info(" β
|
2851 |
-
logger.info(" β
|
2852 |
-
logger.info(" β
|
2853 |
-
logger.info(" β
Improved
|
2854 |
-
logger.info(" β
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2855 |
logger.info("")
|
2856 |
|
2857 |
try:
|
@@ -2861,7 +3676,10 @@ if __name__ == "__main__":
|
|
2861 |
share=False,
|
2862 |
show_error=True,
|
2863 |
favicon_path=None,
|
2864 |
-
ssl_verify=False
|
|
|
|
|
|
|
2865 |
)
|
2866 |
except Exception as e:
|
2867 |
logger.error(f"β Failed to launch application: {e}")
|
|
|
1400 |
]
|
1401 |
|
1402 |
def return_to_landing():
|
1403 |
+
"""Return to landing page with preserved styling"""
|
1404 |
return [
|
1405 |
gr.update(visible=True), # landing_page
|
1406 |
gr.update(visible=False), # signin_page
|
|
|
1481 |
gr.update(visible=False), # signin_page
|
1482 |
gr.update(visible=False), # signup_page
|
1483 |
gr.update(visible=True), # dashboard_page
|
1484 |
+
f"<div class='dashboard-welcome'>Welcome back, <strong>{name}</strong>! π</div>", # welcome message
|
1485 |
f"<div class='balance-amount'>π° {format_currency(current_balance)}</div>", # balance display
|
1486 |
phone, # current_user state
|
1487 |
monthly_income, # income
|
|
|
1504 |
return [
|
1505 |
gr.update(visible=False), gr.update(visible=False),
|
1506 |
gr.update(visible=False), gr.update(visible=True),
|
1507 |
+
f"<div class='dashboard-welcome'>Welcome, <strong>{name}</strong>! (Error loading data)</div>",
|
1508 |
"<div class='balance-amount'>π° 0 PKR</div>",
|
1509 |
phone, 0, 0, *empty_alloc, [], [], [], None, None,
|
1510 |
"No family group", [], []
|
|
|
2066 |
current_balance = db.get_current_balance(current_user) if current_user else 0
|
2067 |
return f"β Error saving receipt: {str(e)}", f"<div class='balance-amount'>π° {format_currency(current_balance)}</div>", [], []
|
2068 |
|
2069 |
+
# ========== I) ENHANCED CUSTOM CSS ==========
|
2070 |
custom_css = """
|
2071 |
+
/* Enhanced CSS for better UI/UX with fixed sizing issues */
|
2072 |
+
:root {
|
2073 |
+
--primary-color: #667eea;
|
2074 |
+
--secondary-color: #764ba2;
|
2075 |
+
--accent-color: #ff6b6b;
|
2076 |
+
--success-color: #48bb78;
|
2077 |
+
--warning-color: #ed8936;
|
2078 |
+
--error-color: #e53e3e;
|
2079 |
+
--text-primary: #2d3748;
|
2080 |
+
--text-secondary: #4a5568;
|
2081 |
+
--bg-light: #f7fafc;
|
2082 |
+
--bg-card: #ffffff;
|
2083 |
+
--border-color: #e2e8f0;
|
2084 |
+
--shadow-light: 0 4px 6px rgba(0, 0, 0, 0.05);
|
2085 |
+
--shadow-medium: 0 10px 25px rgba(0, 0, 0, 0.1);
|
2086 |
+
--shadow-heavy: 0 20px 40px rgba(0, 0, 0, 0.15);
|
2087 |
+
--border-radius: 15px;
|
2088 |
+
--border-radius-small: 8px;
|
2089 |
+
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
2090 |
+
}
|
2091 |
+
|
2092 |
.gradio-container {
|
2093 |
+
max-width: 1400px !important;
|
2094 |
margin: 0 auto !important;
|
2095 |
+
padding: 1rem !important;
|
2096 |
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif !important;
|
2097 |
+
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%) !important;
|
2098 |
+
min-height: 100vh !important;
|
2099 |
}
|
2100 |
|
2101 |
+
/* Fixed Landing Page Styling */
|
2102 |
.landing-hero {
|
2103 |
+
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
2104 |
+
min-height: 85vh;
|
2105 |
+
padding: 4rem 2rem;
|
2106 |
color: white;
|
2107 |
text-align: center;
|
2108 |
+
border-radius: var(--border-radius);
|
2109 |
+
margin: 1rem 0;
|
2110 |
+
box-shadow: var(--shadow-heavy);
|
2111 |
+
position: relative;
|
2112 |
+
overflow: hidden;
|
2113 |
+
}
|
2114 |
+
|
2115 |
+
.landing-hero::before {
|
2116 |
+
content: '';
|
2117 |
+
position: absolute;
|
2118 |
+
top: 0;
|
2119 |
+
left: 0;
|
2120 |
+
right: 0;
|
2121 |
+
bottom: 0;
|
2122 |
+
background: linear-gradient(45deg, rgba(255,255,255,0.1) 0%, transparent 50%, rgba(255,255,255,0.05) 100%);
|
2123 |
+
pointer-events: none;
|
2124 |
}
|
2125 |
|
2126 |
.hero-title {
|
2127 |
+
font-size: clamp(2.5rem, 5vw, 4rem);
|
2128 |
+
font-weight: 800;
|
2129 |
+
margin-bottom: 1.5rem;
|
2130 |
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
|
2131 |
+
background: linear-gradient(45deg, #fff, #f0f8ff);
|
2132 |
+
-webkit-background-clip: text;
|
2133 |
+
-webkit-text-fill-color: transparent;
|
2134 |
+
background-clip: text;
|
2135 |
+
position: relative;
|
2136 |
+
z-index: 1;
|
2137 |
}
|
2138 |
|
2139 |
.hero-subtitle {
|
2140 |
+
font-size: clamp(1.1rem, 2.5vw, 1.6rem);
|
2141 |
+
margin-bottom: 3rem;
|
2142 |
+
opacity: 0.95;
|
2143 |
+
font-weight: 300;
|
2144 |
+
line-height: 1.6;
|
2145 |
+
position: relative;
|
2146 |
+
z-index: 1;
|
2147 |
}
|
2148 |
|
2149 |
.features-grid {
|
2150 |
display: grid;
|
2151 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
2152 |
gap: 2rem;
|
2153 |
margin: 3rem 0;
|
2154 |
+
position: relative;
|
2155 |
+
z-index: 1;
|
2156 |
}
|
2157 |
|
2158 |
.feature-card {
|
2159 |
+
background: rgba(255,255,255,0.15);
|
2160 |
+
backdrop-filter: blur(15px);
|
2161 |
+
border-radius: var(--border-radius);
|
2162 |
+
padding: 2.5rem 2rem;
|
2163 |
text-align: center;
|
2164 |
border: 1px solid rgba(255,255,255,0.2);
|
2165 |
+
transition: var(--transition);
|
2166 |
+
position: relative;
|
2167 |
+
overflow: hidden;
|
2168 |
+
}
|
2169 |
+
|
2170 |
+
.feature-card::before {
|
2171 |
+
content: '';
|
2172 |
+
position: absolute;
|
2173 |
+
top: 0;
|
2174 |
+
left: -100%;
|
2175 |
+
width: 100%;
|
2176 |
+
height: 100%;
|
2177 |
+
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
|
2178 |
+
transition: left 0.8s;
|
2179 |
+
}
|
2180 |
+
|
2181 |
+
.feature-card:hover::before {
|
2182 |
+
left: 100%;
|
2183 |
}
|
2184 |
|
2185 |
.feature-card:hover {
|
2186 |
+
transform: translateY(-8px) scale(1.02);
|
2187 |
+
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
|
2188 |
+
border-color: rgba(255,255,255,0.3);
|
2189 |
}
|
2190 |
|
2191 |
.feature-icon {
|
2192 |
+
font-size: 3.5rem;
|
2193 |
+
margin-bottom: 1.5rem;
|
2194 |
+
display: block;
|
2195 |
+
transform: scale(1);
|
2196 |
+
transition: var(--transition);
|
2197 |
+
}
|
2198 |
+
|
2199 |
+
.feature-card:hover .feature-icon {
|
2200 |
+
transform: scale(1.1) rotate(5deg);
|
2201 |
+
}
|
2202 |
+
|
2203 |
+
.feature-card h3 {
|
2204 |
+
font-size: 1.4rem;
|
2205 |
+
font-weight: 600;
|
2206 |
margin-bottom: 1rem;
|
2207 |
+
color: white;
|
2208 |
}
|
2209 |
|
2210 |
+
.feature-card p {
|
2211 |
+
opacity: 0.9;
|
2212 |
+
line-height: 1.6;
|
2213 |
+
font-size: 1rem;
|
2214 |
+
}
|
2215 |
+
|
2216 |
+
/* Fixed Auth Container Styling */
|
2217 |
.auth-container {
|
2218 |
+
max-width: 480px;
|
2219 |
margin: 2rem auto;
|
2220 |
+
background: var(--bg-card);
|
2221 |
+
border-radius: var(--border-radius);
|
2222 |
+
padding: 3rem 2.5rem;
|
2223 |
+
box-shadow: var(--shadow-heavy);
|
2224 |
+
border: 1px solid var(--border-color);
|
2225 |
+
position: relative;
|
2226 |
+
backdrop-filter: blur(10px);
|
2227 |
}
|
2228 |
|
2229 |
+
.auth-container::before {
|
2230 |
+
content: '';
|
2231 |
+
position: absolute;
|
2232 |
+
top: 0;
|
2233 |
+
left: 0;
|
2234 |
+
right: 0;
|
2235 |
+
height: 4px;
|
2236 |
+
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
|
2237 |
+
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
2238 |
+
}
|
2239 |
+
|
2240 |
+
/* WhatsApp Setup Enhanced */
|
2241 |
.whatsapp-setup {
|
2242 |
background: linear-gradient(135deg, #25D366 0%, #128C7E 100%);
|
2243 |
color: white;
|
2244 |
+
padding: 2.5rem;
|
2245 |
+
border-radius: var(--border-radius);
|
2246 |
margin: 2rem 0;
|
2247 |
text-align: center;
|
2248 |
+
box-shadow: 0 15px 35px rgba(37, 211, 102, 0.3);
|
2249 |
+
position: relative;
|
2250 |
+
overflow: hidden;
|
2251 |
+
}
|
2252 |
+
|
2253 |
+
.whatsapp-setup::before {
|
2254 |
+
content: '';
|
2255 |
+
position: absolute;
|
2256 |
+
top: -50%;
|
2257 |
+
left: -50%;
|
2258 |
+
width: 200%;
|
2259 |
+
height: 200%;
|
2260 |
+
background: linear-gradient(45deg, transparent, rgba(255,255,255,0.05), transparent);
|
2261 |
+
animation: shimmer 3s infinite;
|
2262 |
+
}
|
2263 |
+
|
2264 |
+
@keyframes shimmer {
|
2265 |
+
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
|
2266 |
+
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
|
2267 |
}
|
2268 |
|
2269 |
.whatsapp-steps {
|
2270 |
+
background: rgba(255, 255, 255, 0.15);
|
2271 |
+
backdrop-filter: blur(15px);
|
2272 |
+
border-radius: var(--border-radius-small);
|
2273 |
+
padding: 2rem;
|
2274 |
+
margin: 1.5rem 0;
|
2275 |
border: 1px solid rgba(255, 255, 255, 0.2);
|
2276 |
text-align: left;
|
2277 |
+
position: relative;
|
2278 |
+
z-index: 1;
|
2279 |
+
}
|
2280 |
+
|
2281 |
+
.whatsapp-steps h4 {
|
2282 |
+
color: white;
|
2283 |
+
font-weight: 600;
|
2284 |
+
margin-bottom: 1rem;
|
2285 |
+
font-size: 1.2rem;
|
2286 |
}
|
2287 |
|
2288 |
+
.phone-highlight, .code-highlight {
|
2289 |
+
background: rgba(255, 255, 255, 0.25);
|
2290 |
+
padding: 0.8rem 1.2rem;
|
2291 |
+
border-radius: var(--border-radius-small);
|
2292 |
+
font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
|
2293 |
font-size: 1.1rem;
|
2294 |
font-weight: bold;
|
2295 |
display: inline-block;
|
2296 |
+
margin: 0.8rem 0;
|
2297 |
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
2298 |
+
box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
|
2299 |
}
|
2300 |
|
2301 |
.code-highlight {
|
2302 |
+
border-left: 4px solid rgba(255, 255, 255, 0.5);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2303 |
}
|
2304 |
|
2305 |
+
/* Enhanced Dashboard Styling */
|
2306 |
.dashboard-header {
|
2307 |
+
background: linear-gradient(135deg, var(--text-primary) 0%, var(--text-secondary) 100%);
|
2308 |
color: white;
|
2309 |
+
padding: 2.5rem;
|
2310 |
+
border-radius: var(--border-radius);
|
2311 |
margin-bottom: 2rem;
|
2312 |
text-align: center;
|
2313 |
+
font-size: 1.6rem;
|
2314 |
+
box-shadow: var(--shadow-medium);
|
2315 |
+
position: relative;
|
2316 |
+
overflow: hidden;
|
2317 |
+
}
|
2318 |
+
|
2319 |
+
.dashboard-welcome {
|
2320 |
+
font-size: 1.8rem;
|
2321 |
+
font-weight: 300;
|
2322 |
+
text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
|
2323 |
+
}
|
2324 |
+
|
2325 |
+
.dashboard-welcome strong {
|
2326 |
+
font-weight: 600;
|
2327 |
+
color: #ffd700;
|
2328 |
}
|
2329 |
|
2330 |
.balance-card {
|
2331 |
+
background: linear-gradient(135deg, var(--success-color) 0%, #38a169 100%);
|
2332 |
color: white;
|
2333 |
+
padding: 2.5rem;
|
2334 |
+
border-radius: var(--border-radius);
|
2335 |
text-align: center;
|
2336 |
margin-bottom: 2rem;
|
2337 |
+
box-shadow: var(--shadow-medium);
|
2338 |
+
position: relative;
|
2339 |
+
overflow: hidden;
|
2340 |
+
}
|
2341 |
+
|
2342 |
+
.balance-card::after {
|
2343 |
+
content: 'π°';
|
2344 |
+
position: absolute;
|
2345 |
+
top: -20px;
|
2346 |
+
right: -20px;
|
2347 |
+
font-size: 8rem;
|
2348 |
+
opacity: 0.1;
|
2349 |
+
pointer-events: none;
|
2350 |
}
|
2351 |
|
2352 |
.balance-amount {
|
2353 |
+
font-size: clamp(2rem, 4vw, 3rem);
|
2354 |
+
font-weight: 800;
|
2355 |
+
margin: 1.5rem 0;
|
2356 |
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
2357 |
+
background: linear-gradient(45deg, #fff, #f0fff0);
|
2358 |
+
-webkit-background-clip: text;
|
2359 |
+
-webkit-text-fill-color: transparent;
|
2360 |
+
background-clip: text;
|
2361 |
}
|
2362 |
|
2363 |
+
/* Enhanced Button Styling with Equal Sizes */
|
2364 |
+
.primary-btn, .secondary-btn {
|
2365 |
border: none !important;
|
2366 |
border-radius: 25px !important;
|
2367 |
padding: 1rem 2rem !important;
|
2368 |
font-size: 1.1rem !important;
|
2369 |
font-weight: 600 !important;
|
2370 |
color: white !important;
|
2371 |
+
transition: var(--transition) !important;
|
|
|
2372 |
cursor: pointer !important;
|
2373 |
+
position: relative !important;
|
2374 |
+
overflow: hidden !important;
|
2375 |
+
min-width: 180px !important;
|
2376 |
+
height: 48px !important;
|
2377 |
+
display: inline-flex !important;
|
2378 |
+
align-items: center !important;
|
2379 |
+
justify-content: center !important;
|
2380 |
+
text-decoration: none !important;
|
2381 |
+
box-sizing: border-box !important;
|
2382 |
+
}
|
2383 |
+
|
2384 |
+
.primary-btn {
|
2385 |
+
background: linear-gradient(45deg, var(--accent-color), #ee5a24) !important;
|
2386 |
+
box-shadow: 0 4px 15px rgba(238, 90, 36, 0.4) !important;
|
2387 |
}
|
2388 |
|
2389 |
.primary-btn:hover {
|
2390 |
+
transform: translateY(-3px) !important;
|
2391 |
+
box-shadow: 0 8px 25px rgba(238, 90, 36, 0.6) !important;
|
2392 |
}
|
2393 |
|
2394 |
.secondary-btn {
|
2395 |
background: linear-gradient(45deg, #74b9ff, #0984e3) !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2396 |
box-shadow: 0 4px 15px rgba(116, 185, 255, 0.4) !important;
|
|
|
2397 |
}
|
2398 |
|
2399 |
.secondary-btn:hover {
|
2400 |
+
transform: translateY(-3px) !important;
|
2401 |
+
box-shadow: 0 8px 25px rgba(116, 185, 255, 0.6) !important;
|
2402 |
}
|
2403 |
|
2404 |
+
.primary-btn::before, .secondary-btn::before {
|
2405 |
+
content: '';
|
2406 |
+
position: absolute;
|
2407 |
+
top: 0;
|
2408 |
+
left: -100%;
|
2409 |
+
width: 100%;
|
2410 |
+
height: 100%;
|
2411 |
+
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
|
2412 |
+
transition: left 0.5s;
|
2413 |
+
}
|
2414 |
+
|
2415 |
+
.primary-btn:hover::before, .secondary-btn:hover::before {
|
2416 |
+
left: 100%;
|
2417 |
+
}
|
2418 |
+
|
2419 |
+
/* Enhanced Table Styling */
|
2420 |
.dataframe {
|
2421 |
+
border-radius: var(--border-radius) !important;
|
2422 |
overflow: hidden !important;
|
2423 |
+
box-shadow: var(--shadow-medium) !important;
|
2424 |
+
border: 1px solid var(--border-color) !important;
|
2425 |
+
background: var(--bg-card) !important;
|
2426 |
+
margin: 1rem 0 !important;
|
2427 |
}
|
2428 |
|
2429 |
.dataframe th {
|
2430 |
+
background: linear-gradient(135deg, var(--bg-light) 0%, #edf2f7 100%) !important;
|
2431 |
font-weight: 600 !important;
|
2432 |
+
padding: 1.2rem 1rem !important;
|
2433 |
+
border-bottom: 2px solid var(--border-color) !important;
|
2434 |
+
color: var(--text-primary) !important;
|
2435 |
+
font-size: 0.95rem !important;
|
2436 |
+
text-transform: uppercase !important;
|
2437 |
+
letter-spacing: 0.5px !important;
|
2438 |
}
|
2439 |
|
2440 |
.dataframe td {
|
2441 |
+
padding: 1rem !important;
|
2442 |
border-bottom: 1px solid #f1f5f9 !important;
|
2443 |
+
color: var(--text-secondary) !important;
|
2444 |
+
transition: background-color 0.2s ease !important;
|
2445 |
+
}
|
2446 |
+
|
2447 |
+
.dataframe tr:hover td {
|
2448 |
+
background-color: rgba(102, 126, 234, 0.05) !important;
|
2449 |
+
}
|
2450 |
+
|
2451 |
+
/* Enhanced Tab Styling */
|
2452 |
+
.tab-nav .tab-nav {
|
2453 |
+
border-radius: var(--border-radius) !important;
|
2454 |
+
background: var(--bg-card) !important;
|
2455 |
+
box-shadow: var(--shadow-light) !important;
|
2456 |
+
border: 1px solid var(--border-color) !important;
|
2457 |
+
overflow: hidden !important;
|
2458 |
+
}
|
2459 |
+
|
2460 |
+
.tab-nav button {
|
2461 |
+
background: transparent !important;
|
2462 |
+
border: none !important;
|
2463 |
+
padding: 1rem 1.5rem !important;
|
2464 |
+
font-weight: 500 !important;
|
2465 |
+
color: var(--text-secondary) !important;
|
2466 |
+
transition: var(--transition) !important;
|
2467 |
+
position: relative !important;
|
2468 |
+
}
|
2469 |
+
|
2470 |
+
.tab-nav button:hover {
|
2471 |
+
background: rgba(102, 126, 234, 0.05) !important;
|
2472 |
+
color: var(--primary-color) !important;
|
2473 |
+
}
|
2474 |
+
|
2475 |
+
.tab-nav button.selected {
|
2476 |
+
background: var(--primary-color) !important;
|
2477 |
+
color: white !important;
|
2478 |
+
}
|
2479 |
+
|
2480 |
+
.tab-nav button.selected::after {
|
2481 |
+
content: '';
|
2482 |
+
position: absolute;
|
2483 |
+
bottom: 0;
|
2484 |
+
left: 0;
|
2485 |
+
right: 0;
|
2486 |
+
height: 3px;
|
2487 |
+
background: var(--accent-color);
|
2488 |
+
}
|
2489 |
+
|
2490 |
+
/* Enhanced Form Styling */
|
2491 |
+
.gr-form {
|
2492 |
+
background: var(--bg-card) !important;
|
2493 |
+
border-radius: var(--border-radius) !important;
|
2494 |
+
padding: 2rem !important;
|
2495 |
+
box-shadow: var(--shadow-light) !important;
|
2496 |
+
border: 1px solid var(--border-color) !important;
|
2497 |
+
margin: 1rem 0 !important;
|
2498 |
+
}
|
2499 |
+
|
2500 |
+
.gr-form label {
|
2501 |
+
font-weight: 600 !important;
|
2502 |
+
color: var(--text-primary) !important;
|
2503 |
+
margin-bottom: 0.5rem !important;
|
2504 |
+
display: block !important;
|
2505 |
+
}
|
2506 |
+
|
2507 |
+
.gr-form input, .gr-form textarea, .gr-form select {
|
2508 |
+
border: 2px solid var(--border-color) !important;
|
2509 |
+
border-radius: var(--border-radius-small) !important;
|
2510 |
+
padding: 0.8rem 1rem !important;
|
2511 |
+
font-size: 1rem !important;
|
2512 |
+
transition: var(--transition) !important;
|
2513 |
+
background: var(--bg-card) !important;
|
2514 |
+
color: var(--text-primary) !important;
|
2515 |
+
}
|
2516 |
+
|
2517 |
+
.gr-form input:focus, .gr-form textarea:focus, .gr-form select:focus {
|
2518 |
+
border-color: var(--primary-color) !important;
|
2519 |
+
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
|
2520 |
+
outline: none !important;
|
2521 |
}
|
2522 |
|
2523 |
+
/* Status Messages */
|
2524 |
.status-success {
|
2525 |
+
color: var(--success-color) !important;
|
2526 |
+
background: rgba(72, 187, 120, 0.1) !important;
|
2527 |
+
border: 1px solid rgba(72, 187, 120, 0.2) !important;
|
2528 |
+
padding: 1rem !important;
|
2529 |
+
border-radius: var(--border-radius-small) !important;
|
2530 |
font-weight: 600 !important;
|
2531 |
+
margin: 1rem 0 !important;
|
2532 |
}
|
2533 |
|
2534 |
.status-error {
|
2535 |
+
color: var(--error-color) !important;
|
2536 |
+
background: rgba(229, 62, 62, 0.1) !important;
|
2537 |
+
border: 1px solid rgba(229, 62, 62, 0.2) !important;
|
2538 |
+
padding: 1rem !important;
|
2539 |
+
border-radius: var(--border-radius-small) !important;
|
2540 |
font-weight: 600 !important;
|
2541 |
+
margin: 1rem 0 !important;
|
2542 |
+
}
|
2543 |
+
|
2544 |
+
/* Enhanced Cards and Sections */
|
2545 |
+
.info-card {
|
2546 |
+
background: var(--bg-card);
|
2547 |
+
border-radius: var(--border-radius);
|
2548 |
+
padding: 2rem;
|
2549 |
+
box-shadow: var(--shadow-light);
|
2550 |
+
border: 1px solid var(--border-color);
|
2551 |
+
margin: 1rem 0;
|
2552 |
+
position: relative;
|
2553 |
+
overflow: hidden;
|
2554 |
+
}
|
2555 |
+
|
2556 |
+
.info-card::before {
|
2557 |
+
content: '';
|
2558 |
+
position: absolute;
|
2559 |
+
top: 0;
|
2560 |
+
left: 0;
|
2561 |
+
right: 0;
|
2562 |
+
height: 4px;
|
2563 |
+
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
|
2564 |
+
}
|
2565 |
+
|
2566 |
+
.info-card h3 {
|
2567 |
+
color: var(--text-primary);
|
2568 |
+
font-size: 1.4rem;
|
2569 |
+
font-weight: 600;
|
2570 |
+
margin-bottom: 1rem;
|
2571 |
}
|
2572 |
|
2573 |
+
.info-card p {
|
2574 |
+
color: var(--text-secondary);
|
2575 |
+
line-height: 1.6;
|
2576 |
+
margin-bottom: 1rem;
|
2577 |
+
}
|
2578 |
+
|
2579 |
+
/* Responsive Design Enhancements */
|
2580 |
@media (max-width: 768px) {
|
2581 |
+
.gradio-container {
|
2582 |
+
padding: 0.5rem !important;
|
2583 |
+
}
|
2584 |
+
|
2585 |
.hero-title {
|
2586 |
font-size: 2.5rem;
|
2587 |
}
|
|
|
2592 |
|
2593 |
.features-grid {
|
2594 |
grid-template-columns: 1fr;
|
2595 |
+
gap: 1.5rem;
|
2596 |
}
|
2597 |
|
2598 |
.auth-container {
|
2599 |
margin: 1rem;
|
2600 |
+
padding: 2rem 1.5rem;
|
2601 |
+
}
|
2602 |
+
|
2603 |
+
.balance-amount {
|
2604 |
+
font-size: 2.2rem;
|
2605 |
+
}
|
2606 |
+
|
2607 |
+
.primary-btn, .secondary-btn {
|
2608 |
+
min-width: 150px !important;
|
2609 |
+
font-size: 1rem !important;
|
2610 |
+
padding: 0.9rem 1.5rem !important;
|
2611 |
+
}
|
2612 |
+
|
2613 |
+
.dashboard-welcome {
|
2614 |
+
font-size: 1.4rem;
|
2615 |
+
}
|
2616 |
+
|
2617 |
+
.feature-card {
|
2618 |
+
padding: 2rem 1.5rem;
|
2619 |
+
}
|
2620 |
+
|
2621 |
+
.whatsapp-setup {
|
2622 |
+
padding: 2rem 1.5rem;
|
2623 |
+
}
|
2624 |
+
|
2625 |
+
.whatsapp-steps {
|
2626 |
+
padding: 1.5rem;
|
2627 |
+
}
|
2628 |
+
}
|
2629 |
+
|
2630 |
+
@media (max-width: 480px) {
|
2631 |
+
.hero-title {
|
2632 |
+
font-size: 2rem;
|
2633 |
}
|
2634 |
|
2635 |
.balance-amount {
|
2636 |
font-size: 2rem;
|
2637 |
}
|
2638 |
+
|
2639 |
+
.auth-container {
|
2640 |
+
padding: 2rem 1rem;
|
2641 |
+
}
|
2642 |
+
|
2643 |
+
.primary-btn, .secondary-btn {
|
2644 |
+
min-width: 130px !important;
|
2645 |
+
padding: 0.8rem 1.2rem !important;
|
2646 |
+
}
|
2647 |
}
|
2648 |
|
2649 |
+
/* Loading States */
|
2650 |
.loading {
|
2651 |
opacity: 0.6;
|
2652 |
pointer-events: none;
|
2653 |
+
position: relative;
|
2654 |
+
}
|
2655 |
+
|
2656 |
+
.loading::after {
|
2657 |
+
content: '';
|
2658 |
+
position: absolute;
|
2659 |
+
top: 50%;
|
2660 |
+
left: 50%;
|
2661 |
+
width: 20px;
|
2662 |
+
height: 20px;
|
2663 |
+
margin: -10px 0 0 -10px;
|
2664 |
+
border: 2px solid transparent;
|
2665 |
+
border-top-color: var(--primary-color);
|
2666 |
+
border-radius: 50%;
|
2667 |
+
animation: spin 1s linear infinite;
|
2668 |
+
}
|
2669 |
+
|
2670 |
+
@keyframes spin {
|
2671 |
+
0% { transform: rotate(0deg); }
|
2672 |
+
100% { transform: rotate(360deg); }
|
2673 |
}
|
2674 |
|
2675 |
/* Animations */
|
2676 |
@keyframes fadeIn {
|
2677 |
+
from {
|
2678 |
+
opacity: 0;
|
2679 |
+
transform: translateY(30px);
|
2680 |
+
}
|
2681 |
+
to {
|
2682 |
+
opacity: 1;
|
2683 |
+
transform: translateY(0);
|
2684 |
+
}
|
2685 |
+
}
|
2686 |
+
|
2687 |
+
@keyframes slideIn {
|
2688 |
+
from {
|
2689 |
+
opacity: 0;
|
2690 |
+
transform: translateX(-30px);
|
2691 |
+
}
|
2692 |
+
to {
|
2693 |
+
opacity: 1;
|
2694 |
+
transform: translateX(0);
|
2695 |
+
}
|
2696 |
}
|
2697 |
|
2698 |
.fade-in {
|
2699 |
+
animation: fadeIn 0.6s ease-out;
|
2700 |
+
}
|
2701 |
+
|
2702 |
+
.slide-in {
|
2703 |
+
animation: slideIn 0.6s ease-out;
|
2704 |
+
}
|
2705 |
+
|
2706 |
+
/* Enhanced Gradient Backgrounds */
|
2707 |
+
.gradient-bg-1 {
|
2708 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
2709 |
+
}
|
2710 |
+
|
2711 |
+
.gradient-bg-2 {
|
2712 |
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
2713 |
+
}
|
2714 |
+
|
2715 |
+
.gradient-bg-3 {
|
2716 |
+
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
2717 |
+
}
|
2718 |
+
|
2719 |
+
.gradient-bg-4 {
|
2720 |
+
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
2721 |
+
}
|
2722 |
+
|
2723 |
+
/* Chart Container Enhancements */
|
2724 |
+
.plotly-graph-div {
|
2725 |
+
border-radius: var(--border-radius) !important;
|
2726 |
+
box-shadow: var(--shadow-light) !important;
|
2727 |
+
border: 1px solid var(--border-color) !important;
|
2728 |
+
background: var(--bg-card) !important;
|
2729 |
+
margin: 1rem 0 !important;
|
2730 |
+
}
|
2731 |
+
|
2732 |
+
/* File Upload Styling */
|
2733 |
+
.file-upload {
|
2734 |
+
border: 2px dashed var(--border-color) !important;
|
2735 |
+
border-radius: var(--border-radius) !important;
|
2736 |
+
padding: 2rem !important;
|
2737 |
+
text-align: center !important;
|
2738 |
+
background: var(--bg-light) !important;
|
2739 |
+
transition: var(--transition) !important;
|
2740 |
+
}
|
2741 |
+
|
2742 |
+
.file-upload:hover {
|
2743 |
+
border-color: var(--primary-color) !important;
|
2744 |
+
background: rgba(102, 126, 234, 0.05) !important;
|
2745 |
+
}
|
2746 |
+
|
2747 |
+
/* Enhanced Accordion Styling */
|
2748 |
+
.gr-accordion {
|
2749 |
+
border-radius: var(--border-radius) !important;
|
2750 |
+
border: 1px solid var(--border-color) !important;
|
2751 |
+
overflow: hidden !important;
|
2752 |
+
box-shadow: var(--shadow-light) !important;
|
2753 |
+
}
|
2754 |
+
|
2755 |
+
.gr-accordion summary {
|
2756 |
+
background: var(--bg-light) !important;
|
2757 |
+
padding: 1rem 1.5rem !important;
|
2758 |
+
font-weight: 600 !important;
|
2759 |
+
color: var(--text-primary) !important;
|
2760 |
+
cursor: pointer !important;
|
2761 |
+
transition: var(--transition) !important;
|
2762 |
+
}
|
2763 |
+
|
2764 |
+
.gr-accordion summary:hover {
|
2765 |
+
background: rgba(102, 126, 234, 0.05) !important;
|
2766 |
+
}
|
2767 |
+
|
2768 |
+
.gr-accordion[open] summary {
|
2769 |
+
background: var(--primary-color) !important;
|
2770 |
+
color: white !important;
|
2771 |
+
}
|
2772 |
+
|
2773 |
+
/* Scrollbar Styling */
|
2774 |
+
::-webkit-scrollbar {
|
2775 |
+
width: 8px;
|
2776 |
+
height: 8px;
|
2777 |
+
}
|
2778 |
+
|
2779 |
+
::-webkit-scrollbar-track {
|
2780 |
+
background: var(--bg-light);
|
2781 |
+
border-radius: 4px;
|
2782 |
+
}
|
2783 |
+
|
2784 |
+
::-webkit-scrollbar-thumb {
|
2785 |
+
background: var(--border-color);
|
2786 |
+
border-radius: 4px;
|
2787 |
+
transition: var(--transition);
|
2788 |
+
}
|
2789 |
+
|
2790 |
+
::-webkit-scrollbar-thumb:hover {
|
2791 |
+
background: var(--text-secondary);
|
2792 |
}
|
2793 |
"""
|
2794 |
|
|
|
2799 |
receipt_data = gr.State({})
|
2800 |
|
2801 |
# ===== LANDING PAGE =====
|
2802 |
+
with gr.Column(visible=True, elem_classes="fade-in") as landing_page:
|
2803 |
gr.HTML("""
|
2804 |
<div class="landing-hero">
|
2805 |
<div class="hero-title">π¦ FinGenius Pro</div>
|
|
|
2809 |
<div class="feature-card">
|
2810 |
<div class="feature-icon">π°</div>
|
2811 |
<h3>Smart Balance Tracking</h3>
|
2812 |
+
<p>Real-time balance monitoring with intelligent spending alerts and comprehensive financial insights</p>
|
2813 |
</div>
|
2814 |
<div class="feature-card">
|
2815 |
<div class="feature-icon">π±</div>
|
2816 |
<h3>WhatsApp Integration</h3>
|
2817 |
+
<p>Get instant notifications for every expense, budget alert, and financial milestone directly on WhatsApp</p>
|
2818 |
</div>
|
2819 |
<div class="feature-card">
|
2820 |
<div class="feature-icon">π</div>
|
2821 |
<h3>Advanced Analytics</h3>
|
2822 |
+
<p>Beautiful interactive charts and detailed insights to track spending patterns and financial trends</p>
|
2823 |
</div>
|
2824 |
<div class="feature-card">
|
2825 |
<div class="feature-icon">π§Ύ</div>
|
2826 |
+
<h3>AI Receipt Scanning</h3>
|
2827 |
+
<p>Revolutionary OCR technology to automatically extract expense data from receipt photos with high accuracy</p>
|
2828 |
</div>
|
2829 |
<div class="feature-card">
|
2830 |
<div class="feature-icon">πͺ</div>
|
2831 |
+
<h3>Family Finance Hub</h3>
|
2832 |
+
<p>Create family groups to collaboratively manage household finances, budgets, and shared expenses</p>
|
2833 |
</div>
|
2834 |
<div class="feature-card">
|
2835 |
<div class="feature-icon">π</div>
|
2836 |
+
<h3>Bank-Level Security</h3>
|
2837 |
+
<p>Military-grade encryption, secure authentication, and privacy-first design to protect your financial data</p>
|
2838 |
</div>
|
2839 |
</div>
|
2840 |
</div>
|
2841 |
""")
|
2842 |
|
2843 |
+
with gr.Row(equal_height=True):
|
2844 |
with gr.Column(scale=1):
|
2845 |
signin_btn = gr.Button("π Sign In", variant="primary", elem_classes="primary-btn", size="lg")
|
2846 |
with gr.Column(scale=1):
|
2847 |
signup_btn = gr.Button("β¨ Create Account", variant="secondary", elem_classes="secondary-btn", size="lg")
|
2848 |
|
2849 |
# ===== SIGN IN PAGE =====
|
2850 |
+
with gr.Column(visible=False, elem_classes="fade-in") as signin_page:
|
2851 |
with gr.Column(elem_classes="auth-container"):
|
2852 |
+
gr.HTML("<h2 style='text-align: center; color: #2d3748; margin-bottom: 2rem; font-weight: 600;'>π Welcome Back to FinGenius Pro</h2>")
|
2853 |
|
2854 |
signin_phone = gr.Textbox(
|
2855 |
label="π± WhatsApp Number",
|
2856 |
placeholder="+92XXXXXXXXXX",
|
2857 |
+
info="Enter your registered WhatsApp number (Pakistan format)"
|
2858 |
)
|
2859 |
signin_password = gr.Textbox(
|
2860 |
label="π Password",
|
|
|
2862 |
placeholder="Enter your secure password"
|
2863 |
)
|
2864 |
|
2865 |
+
with gr.Row(equal_height=True):
|
2866 |
+
submit_signin = gr.Button("Sign In", variant="primary", elem_classes="primary-btn", scale=1)
|
2867 |
+
back_to_landing_1 = gr.Button("β Back", variant="secondary", elem_classes="secondary-btn", scale=1)
|
2868 |
|
2869 |
+
signin_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
2870 |
|
2871 |
# ===== SIGN UP PAGE =====
|
2872 |
+
with gr.Column(visible=False, elem_classes="fade-in") as signup_page:
|
2873 |
with gr.Column(elem_classes="auth-container"):
|
2874 |
+
gr.HTML("<h2 style='text-align: center; color: #2d3748; margin-bottom: 2rem; font-weight: 600;'>β¨ Create Your FinGenius Pro Account</h2>")
|
2875 |
|
2876 |
signup_name = gr.Textbox(
|
2877 |
label="π€ Full Name",
|
|
|
2880 |
signup_phone = gr.Textbox(
|
2881 |
label="π± WhatsApp Number",
|
2882 |
placeholder="+92XXXXXXXXXX",
|
2883 |
+
info="This will be used for financial notifications"
|
2884 |
)
|
2885 |
signup_password = gr.Textbox(
|
2886 |
label="π Create Password",
|
|
|
2893 |
placeholder="Re-enter your password"
|
2894 |
)
|
2895 |
|
2896 |
+
# Enhanced WhatsApp Setup Instructions
|
2897 |
gr.HTML("""
|
2898 |
<div class='whatsapp-setup'>
|
2899 |
+
<h3>π± Enable WhatsApp Financial Alerts</h3>
|
2900 |
+
<p style='font-size: 1.2rem; margin-bottom: 2rem; font-weight: 300;'>Get instant notifications for all your financial activities. Follow these simple steps:</p>
|
2901 |
|
2902 |
<div class='whatsapp-steps'>
|
2903 |
<h4>Step 1: Save the Bot Number</h4>
|
2904 |
<p>Add this Twilio WhatsApp Sandbox number to your contacts:</p>
|
2905 |
<div class='phone-highlight'>+1 (415) 523-8886</div>
|
2906 |
+
<p style='font-size: 0.9rem; opacity: 0.8; margin-top: 0.5rem;'>Save as "FinGenius Bot" in your phone</p>
|
2907 |
</div>
|
2908 |
|
2909 |
<div class='whatsapp-steps'>
|
|
|
2911 |
<p>Send this exact message to the number above:</p>
|
2912 |
<div class='code-highlight'>join catch-manner</div>
|
2913 |
<p style='font-size: 0.9rem; opacity: 0.8; margin-top: 0.5rem;'>
|
2914 |
+
β οΈ <strong>Critical:</strong> You must send this exact code to activate the sandbox.
|
2915 |
</p>
|
2916 |
</div>
|
2917 |
|
2918 |
<div class='whatsapp-steps'>
|
2919 |
<h4>Step 3: Confirm Registration</h4>
|
2920 |
<p>After sending the code, register your FinGenius account with the <strong>same phone number</strong> you used to message the bot.</p>
|
2921 |
+
<p style='font-size: 0.9rem; opacity: 0.8;'>The phone numbers must match exactly for notifications to work.</p>
|
2922 |
</div>
|
2923 |
|
2924 |
<div class='whatsapp-steps'>
|
2925 |
+
<h4>Step 4: Start Receiving Smart Alerts</h4>
|
2926 |
<p>You'll receive instant WhatsApp notifications for:</p>
|
2927 |
+
<ul style='text-align: left; margin-left: 1.5rem; opacity: 0.9; line-height: 1.8;'>
|
2928 |
<li>β
Account registration confirmation</li>
|
2929 |
+
<li>π° Balance updates and additions</li>
|
2930 |
+
<li>πΈ Real-time expense notifications</li>
|
2931 |
<li>π§Ύ Receipt processing confirmations</li>
|
2932 |
+
<li>π Investment tracking updates</li>
|
2933 |
+
<li>π¨ Budget alerts and overspending warnings</li>
|
2934 |
+
<li>π Weekly financial summaries</li>
|
2935 |
+
<li>πͺ Family group activities</li>
|
2936 |
</ul>
|
2937 |
</div>
|
2938 |
</div>
|
2939 |
""")
|
2940 |
|
2941 |
+
with gr.Row(equal_height=True):
|
2942 |
+
submit_signup = gr.Button("Complete Registration", variant="primary", elem_classes="primary-btn", scale=1)
|
2943 |
+
back_to_landing_2 = gr.Button("β Back", variant="secondary", elem_classes="secondary-btn", scale=1)
|
2944 |
|
2945 |
+
signup_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
2946 |
|
2947 |
# ===== DASHBOARD PAGE =====
|
2948 |
+
with gr.Column(visible=False, elem_classes="fade-in") as dashboard_page:
|
2949 |
+
# Enhanced Dashboard Header
|
2950 |
welcome_message = gr.HTML("", elem_classes="dashboard-header")
|
2951 |
|
2952 |
+
# Enhanced Current Balance Display
|
2953 |
with gr.Column(elem_classes="balance-card"):
|
2954 |
balance_display = gr.HTML("<div class='balance-amount'>π° 0 PKR</div>")
|
2955 |
|
2956 |
with gr.Row():
|
2957 |
with gr.Column(scale=2):
|
2958 |
+
balance_amount = gr.Number(
|
2959 |
+
label="π° Add to Balance (PKR)",
|
2960 |
+
minimum=1,
|
2961 |
+
step=100,
|
2962 |
+
value=0,
|
2963 |
+
info="Add money from salary, bonus, or other income sources"
|
2964 |
+
)
|
2965 |
+
balance_description = gr.Textbox(
|
2966 |
+
label="Description",
|
2967 |
+
placeholder="e.g., Monthly salary, freelance payment, gift money",
|
2968 |
+
info="Optional: Add a note about this income"
|
2969 |
+
)
|
2970 |
with gr.Column(scale=1):
|
2971 |
+
add_balance_btn = gr.Button("Add Balance", variant="primary", elem_classes="primary-btn", size="lg")
|
2972 |
|
2973 |
+
balance_status = gr.Textbox(label="Balance Status", interactive=False, elem_classes="status-display")
|
2974 |
|
2975 |
with gr.Tabs(elem_classes="tab-nav"):
|
2976 |
+
# Enhanced Dashboard Overview Tab
|
2977 |
with gr.Tab("π Dashboard Overview"):
|
2978 |
gr.HTML("""
|
2979 |
+
<div class="info-card gradient-bg-2" style="color: white; text-align: center; padding: 3rem; border-radius: 15px; margin: 2rem 0;">
|
2980 |
+
<h2 style="font-size: 2.2rem; font-weight: 600; margin-bottom: 1rem;">π Welcome to FinGenius Pro!</h2>
|
2981 |
+
<p style="font-size: 1.3rem; opacity: 0.95; line-height: 1.6; font-weight: 300;">Your comprehensive financial management solution is ready. Let's build your financial future together!</p>
|
2982 |
</div>
|
2983 |
""")
|
2984 |
|
2985 |
with gr.Row():
|
2986 |
+
with gr.Column():
|
2987 |
+
gr.HTML("""
|
2988 |
+
<div class="info-card">
|
2989 |
+
<h3>π Quick Start Guide</h3>
|
2990 |
+
<ol style="text-align: left; margin-left: 1.5rem; line-height: 2; color: #4a5568;">
|
2991 |
+
<li><strong>π° Add Initial Balance:</strong> Use the balance card above to add your starting funds</li>
|
2992 |
+
<li><strong>π Set Financial Goals:</strong> Navigate to "Income & Goals" to set your monthly income and savings targets</li>
|
2993 |
+
<li><strong>π Plan Your Budget:</strong> Use "Budget Planner" to allocate money across expense categories</li>
|
2994 |
+
<li><strong>πΈ Track Daily Expenses:</strong> Log your spending in "Expense Tracker" with automatic categorization</li>
|
2995 |
+
<li><strong>π· Scan Receipts:</strong> Use "Receipt Scan" for AI-powered expense extraction from photos</li>
|
2996 |
+
<li><strong>π Monitor Investments:</strong> Keep track of your investment portfolio and growth</li>
|
2997 |
+
<li><strong>πͺ Family Finance:</strong> Create or join family groups for collaborative budgeting</li>
|
2998 |
+
<li><strong>π Analyze Trends:</strong> Review spending patterns and balance trends in analytics</li>
|
2999 |
+
</ol>
|
3000 |
+
</div>
|
3001 |
+
""")
|
3002 |
+
|
3003 |
+
with gr.Column():
|
3004 |
+
gr.HTML("""
|
3005 |
+
<div class="info-card">
|
3006 |
+
<h3>π― Pro Tips for Success</h3>
|
3007 |
+
<ul style="text-align: left; margin-left: 1.5rem; line-height: 2; color: #4a5568;">
|
3008 |
+
<li><strong>π Enable WhatsApp Alerts:</strong> Get real-time notifications for all financial activities</li>
|
3009 |
+
<li><strong>π
Daily Habit:</strong> Log expenses immediately to maintain accurate records</li>
|
3010 |
+
<li><strong>π― Set Realistic Goals:</strong> Start with achievable savings targets and increase gradually</li>
|
3011 |
+
<li><strong>π Weekly Reviews:</strong> Check your spending patterns every week</li>
|
3012 |
+
<li><strong>π·οΈ Categorize Properly:</strong> Use specific categories for better insights</li>
|
3013 |
+
<li><strong>π‘ Use Receipt Scanner:</strong> Save time with AI-powered expense extraction</li>
|
3014 |
+
<li><strong>π¨βπ©βπ§βπ¦ Family Collaboration:</strong> Share financial goals with family members</li>
|
3015 |
+
<li><strong>π Track ROI:</strong> Monitor your investment performance regularly</li>
|
3016 |
+
</ul>
|
3017 |
+
</div>
|
3018 |
+
""")
|
3019 |
+
|
3020 |
+
# Enhanced Income & Goals Tab
|
3021 |
with gr.Tab("π₯ Income & Goals"):
|
3022 |
+
gr.HTML("""
|
3023 |
+
<div class="info-card gradient-bg-3" style="color: white; text-align: center; padding: 2.5rem; margin-bottom: 2rem;">
|
3024 |
+
<h3 style="font-size: 1.8rem; margin-bottom: 1rem;">π΅ Financial Goal Setting</h3>
|
3025 |
+
<p style="font-size: 1.1rem; opacity: 0.9;">Set your monthly income and savings goals to create a personalized budget plan</p>
|
3026 |
+
</div>
|
3027 |
+
""")
|
3028 |
|
3029 |
with gr.Row():
|
3030 |
+
with gr.Column():
|
3031 |
+
income = gr.Number(
|
3032 |
+
label="π΅ Monthly Income (PKR)",
|
3033 |
+
minimum=0,
|
3034 |
+
step=1000,
|
3035 |
+
value=0,
|
3036 |
+
info="Enter your total monthly income from all sources"
|
3037 |
+
)
|
3038 |
+
with gr.Column():
|
3039 |
+
savings_goal = gr.Number(
|
3040 |
+
label="π― Monthly Savings Goal (PKR)",
|
3041 |
+
minimum=0,
|
3042 |
+
step=1000,
|
3043 |
+
value=0,
|
3044 |
+
info="How much do you want to save each month?"
|
3045 |
+
)
|
3046 |
+
|
3047 |
+
update_btn = gr.Button("πΎ Update Financial Information", variant="primary", elem_classes="primary-btn", size="lg")
|
3048 |
+
income_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
3049 |
|
3050 |
+
gr.HTML("""
|
3051 |
+
<div class="info-card">
|
3052 |
+
<h3>π‘ Smart Financial Planning Tips</h3>
|
3053 |
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin-top: 1rem;">
|
3054 |
+
<div style="background: #e6fffa; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #38b2ac;">
|
3055 |
+
<h4 style="color: #2d3748; margin-bottom: 0.5rem;">50/30/20 Rule</h4>
|
3056 |
+
<p style="color: #4a5568; font-size: 0.9rem;">50% needs, 30% wants, 20% savings & debt repayment</p>
|
3057 |
+
</div>
|
3058 |
+
<div style="background: #fef5e7; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #ed8936;">
|
3059 |
+
<h4 style="color: #2d3748; margin-bottom: 0.5rem;">Emergency Fund</h4>
|
3060 |
+
<p style="color: #4a5568; font-size: 0.9rem;">Aim for 3-6 months of expenses in emergency savings</p>
|
3061 |
+
</div>
|
3062 |
+
<div style="background: #e6ffed; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #48bb78;">
|
3063 |
+
<h4 style="color: #2d3748; margin-bottom: 0.5rem;">Investment Goal</h4>
|
3064 |
+
<p style="color: #4a5568; font-size: 0.9rem;">Consider investing 10-15% of income for long-term growth</p>
|
3065 |
+
</div>
|
3066 |
+
</div>
|
3067 |
+
</div>
|
3068 |
+
""")
|
3069 |
|
3070 |
+
# Enhanced Budget Planner Tab
|
3071 |
with gr.Tab("π Budget Planner"):
|
3072 |
+
gr.HTML("""
|
3073 |
+
<div class="info-card gradient-bg-4" style="color: white; text-align: center; padding: 2.5rem; margin-bottom: 2rem;">
|
3074 |
+
<h3 style="font-size: 1.8rem; margin-bottom: 1rem;">πΌ Smart Budget Allocation</h3>
|
3075 |
+
<p style="font-size: 1.1rem; opacity: 0.9;">Distribute your monthly income across different expense categories for optimal financial management</p>
|
3076 |
+
</div>
|
3077 |
+
""")
|
3078 |
|
3079 |
with gr.Column():
|
3080 |
allocation_inputs = []
|
3081 |
+
|
3082 |
+
# Group categories for better layout
|
3083 |
+
essential_categories = ["Housing (Rent/Mortgage)", "Utilities (Electricity/Water)", "Groceries", "Transportation", "Healthcare"]
|
3084 |
+
lifestyle_categories = ["Dining Out", "Entertainment", "Personal Care", "Education"]
|
3085 |
+
financial_categories = ["Debt Payments", "Savings", "Investments", "Charity", "Miscellaneous"]
|
3086 |
+
|
3087 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 1.5rem 0 1rem 0;'>π Essential Expenses</h4>")
|
3088 |
with gr.Row():
|
3089 |
+
for category in essential_categories:
|
3090 |
+
alloc = gr.Number(
|
3091 |
+
label=f"π·οΈ {category}",
|
3092 |
+
minimum=0,
|
3093 |
+
step=100,
|
3094 |
+
value=0,
|
3095 |
+
info=f"Monthly budget for {category.lower()}"
|
3096 |
+
)
|
3097 |
allocation_inputs.append(alloc)
|
3098 |
+
|
3099 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 1.5rem 0 1rem 0;'>π― Lifestyle & Personal</h4>")
|
3100 |
+
with gr.Row():
|
3101 |
+
for category in lifestyle_categories:
|
3102 |
+
alloc = gr.Number(
|
3103 |
+
label=f"π·οΈ {category}",
|
3104 |
+
minimum=0,
|
3105 |
+
step=100,
|
3106 |
+
value=0,
|
3107 |
+
info=f"Monthly budget for {category.lower()}"
|
3108 |
+
)
|
3109 |
+
allocation_inputs.append(alloc)
|
3110 |
+
|
3111 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 1.5rem 0 1rem 0;'>π° Financial & Others</h4>")
|
3112 |
with gr.Row():
|
3113 |
+
for category in financial_categories:
|
3114 |
+
alloc = gr.Number(
|
3115 |
+
label=f"π·οΈ {category}",
|
3116 |
+
minimum=0,
|
3117 |
+
step=100,
|
3118 |
+
value=0,
|
3119 |
+
info=f"Monthly allocation for {category.lower()}"
|
3120 |
+
)
|
3121 |
allocation_inputs.append(alloc)
|
3122 |
|
3123 |
allocate_btn = gr.Button("πΎ Save Budget Allocations", variant="primary", elem_classes="primary-btn", size="lg")
|
3124 |
+
allocation_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
3125 |
|
3126 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 2rem 0 1rem 0;'>π Current Budget Overview</h4>")
|
3127 |
expense_table = gr.Dataframe(
|
3128 |
+
headers=["Category", "Allocated (PKR)", "Spent (PKR)", "Remaining (PKR)", "Last Updated"],
|
3129 |
interactive=False,
|
3130 |
+
wrap=True,
|
3131 |
+
elem_classes="enhanced-table"
|
3132 |
)
|
3133 |
|
3134 |
+
# Enhanced Receipt Scan Tab
|
3135 |
with gr.Tab("π· Receipt Scan"):
|
3136 |
gr.HTML("""
|
3137 |
+
<div class="info-card gradient-bg-1" style="color: white; text-align: center; padding: 3rem; margin-bottom: 2rem;">
|
3138 |
+
<h2 style="font-size: 2rem; margin-bottom: 1rem;">π§Ύ AI-Powered Receipt Scanner</h2>
|
3139 |
+
<p style="font-size: 1.2rem; opacity: 0.95; font-weight: 300;">Transform your receipt photos into digital expense records with advanced OCR technology!</p>
|
3140 |
+
<div style="margin-top: 2rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.5rem;">
|
3141 |
+
<div style="background: rgba(255,255,255,0.1); padding: 1.5rem; border-radius: 10px;">
|
3142 |
+
<div style="font-size: 2rem; margin-bottom: 0.5rem;">πΈ</div>
|
3143 |
+
<h4>Upload Photo</h4>
|
3144 |
+
<p style="font-size: 0.9rem; opacity: 0.8;">Take or upload receipt image</p>
|
3145 |
+
</div>
|
3146 |
+
<div style="background: rgba(255,255,255,0.1); padding: 1.5rem; border-radius: 10px;">
|
3147 |
+
<div style="font-size: 2rem; margin-bottom: 0.5rem;">π€</div>
|
3148 |
+
<h4>AI Processing</h4>
|
3149 |
+
<p style="font-size: 0.9rem; opacity: 0.8;">Extract data automatically</p>
|
3150 |
+
</div>
|
3151 |
+
<div style="background: rgba(255,255,255,0.1); padding: 1.5rem; border-radius: 10px;">
|
3152 |
+
<div style="font-size: 2rem; margin-bottom: 0.5rem;">βοΈ</div>
|
3153 |
+
<h4>Verify & Save</h4>
|
3154 |
+
<p style="font-size: 0.9rem; opacity: 0.8;">Review and confirm details</p>
|
3155 |
+
</div>
|
3156 |
+
</div>
|
3157 |
</div>
|
3158 |
""")
|
3159 |
|
3160 |
with gr.Row():
|
3161 |
with gr.Column(scale=1):
|
3162 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>π€ Upload Receipt Image</h4>")
|
3163 |
|
3164 |
receipt_image = gr.File(
|
3165 |
label="π· Receipt Image",
|
3166 |
+
file_types=["image/jpeg", "image/jpg", "image/png", "image/bmp", "image/tiff", "image/webp"],
|
3167 |
+
elem_classes="file-upload"
|
3168 |
)
|
3169 |
|
3170 |
process_receipt_btn = gr.Button(
|
3171 |
+
"π Process Receipt with AI",
|
3172 |
variant="primary",
|
3173 |
elem_classes="primary-btn",
|
3174 |
size="lg"
|
3175 |
)
|
3176 |
|
3177 |
+
receipt_status = gr.Textbox(label="Processing Status", interactive=False, elem_classes="status-display")
|
3178 |
|
3179 |
+
# Enhanced Image Preview
|
3180 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 1.5rem 0 1rem 0;'>πΈ Receipt Preview</h4>")
|
3181 |
receipt_preview = gr.Image(
|
3182 |
label="Receipt Preview",
|
3183 |
+
type="filepath",
|
3184 |
+
elem_classes="receipt-preview"
|
3185 |
)
|
3186 |
|
3187 |
with gr.Column(scale=1):
|
3188 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>βοΈ Verify & Edit Extracted Data</h4>")
|
3189 |
|
3190 |
extracted_merchant = gr.Textbox(
|
3191 |
label="πͺ Merchant Name",
|
3192 |
placeholder="Store/Restaurant name",
|
3193 |
+
info="AI-detected merchant name (edit if incorrect)"
|
3194 |
)
|
3195 |
|
3196 |
with gr.Row():
|
|
|
3198 |
label="π° Total Amount (PKR)",
|
3199 |
minimum=0,
|
3200 |
step=0.01,
|
3201 |
+
value=0,
|
3202 |
+
info="Total amount from receipt"
|
3203 |
)
|
3204 |
extracted_date = gr.Textbox(
|
3205 |
+
label="π
Purchase Date",
|
3206 |
+
placeholder="YYYY-MM-DD or DD/MM/YYYY",
|
3207 |
+
info="Date of purchase"
|
3208 |
)
|
3209 |
|
3210 |
extracted_category = gr.Dropdown(
|
3211 |
choices=EXPENSE_CATEGORIES,
|
3212 |
+
label="π·οΈ Expense Category",
|
3213 |
value="Miscellaneous",
|
3214 |
info="AI-suggested category (you can change it)"
|
3215 |
)
|
3216 |
|
3217 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 1.5rem 0 1rem 0;'>π Receipt Items (Optional)</h4>")
|
3218 |
line_items_table = gr.Dataframe(
|
3219 |
+
headers=["Item Name", "Price (PKR)"],
|
3220 |
datatype=["str", "number"],
|
3221 |
row_count=5,
|
3222 |
col_count=2,
|
3223 |
interactive=True,
|
3224 |
+
label="Individual items from receipt",
|
3225 |
+
elem_classes="line-items-table"
|
3226 |
)
|
3227 |
|
3228 |
save_receipt_btn = gr.Button(
|
3229 |
+
"πΎ Save as Expense Record",
|
3230 |
variant="primary",
|
3231 |
elem_classes="primary-btn",
|
3232 |
size="lg"
|
3233 |
)
|
3234 |
|
3235 |
+
# Enhanced Receipt History
|
3236 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 2rem 0 1rem 0;'>π§Ύ Recent Receipt Processing History</h4>")
|
3237 |
receipts_table = gr.Dataframe(
|
3238 |
+
headers=["Receipt ID", "Merchant", "Amount", "Date", "Category", "AI Confidence", "Status", "Processed On"],
|
3239 |
interactive=False,
|
3240 |
+
wrap=True,
|
3241 |
+
elem_classes="receipts-history-table"
|
3242 |
)
|
3243 |
|
3244 |
+
# Enhanced Expense Tracker Tab
|
3245 |
with gr.Tab("πΈ Expense Tracker"):
|
3246 |
+
gr.HTML("""
|
3247 |
+
<div class="info-card gradient-bg-2" style="color: white; text-align: center; padding: 2.5rem; margin-bottom: 2rem;">
|
3248 |
+
<h3 style="font-size: 1.8rem; margin-bottom: 1rem;">πΈ Smart Expense Tracking</h3>
|
3249 |
+
<p style="font-size: 1.1rem; opacity: 0.9;">Log your daily expenses with intelligent categorization and recurring expense management</p>
|
3250 |
+
</div>
|
3251 |
+
""")
|
3252 |
+
|
3253 |
with gr.Row():
|
3254 |
+
with gr.Column(scale=1):
|
3255 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>β Record New Expense</h4>")
|
3256 |
+
|
3257 |
+
expense_category = gr.Dropdown(
|
3258 |
+
choices=EXPENSE_CATEGORIES,
|
3259 |
+
label="π·οΈ Expense Category",
|
3260 |
+
info="Select the most appropriate category"
|
3261 |
+
)
|
3262 |
+
|
3263 |
+
with gr.Row():
|
3264 |
+
expense_amount = gr.Number(
|
3265 |
+
label="π° Amount (PKR)",
|
3266 |
+
minimum=1,
|
3267 |
+
step=100,
|
3268 |
+
value=0,
|
3269 |
+
info="How much did you spend?"
|
3270 |
+
)
|
3271 |
+
expense_description = gr.Textbox(
|
3272 |
+
label="π Description",
|
3273 |
+
placeholder="What did you buy? Where?",
|
3274 |
+
info="Add details about this expense"
|
3275 |
+
)
|
3276 |
|
3277 |
with gr.Accordion("π Recurring Expense Settings", open=False):
|
3278 |
+
is_recurring = gr.Checkbox(
|
3279 |
+
label="This is a recurring expense",
|
3280 |
+
info="Check if this expense repeats regularly"
|
3281 |
+
)
|
3282 |
+
recurrence_pattern = gr.Dropdown(
|
3283 |
+
choices=RECURRENCE_PATTERNS,
|
3284 |
+
label="π Frequency",
|
3285 |
+
info="How often does this expense occur?"
|
3286 |
+
)
|
3287 |
|
3288 |
+
record_expense_btn = gr.Button(
|
3289 |
+
"πΈ Record Expense",
|
3290 |
+
variant="primary",
|
3291 |
+
elem_classes="primary-btn",
|
3292 |
+
size="lg"
|
3293 |
+
)
|
3294 |
+
expense_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
3295 |
|
3296 |
+
with gr.Column(scale=1):
|
3297 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>π Financial Analytics</h4>")
|
3298 |
+
|
3299 |
+
with gr.Row():
|
3300 |
+
months_history = gr.Slider(
|
3301 |
+
1, 12,
|
3302 |
+
value=3,
|
3303 |
+
step=1,
|
3304 |
+
label="π
Analysis Period (Months)",
|
3305 |
+
info="Select how many months of data to analyze"
|
3306 |
+
)
|
3307 |
+
update_charts_btn = gr.Button(
|
3308 |
+
"π Update Analytics",
|
3309 |
+
variant="secondary",
|
3310 |
+
elem_classes="secondary-btn"
|
3311 |
+
)
|
3312 |
+
|
3313 |
+
spending_chart = gr.Plot(
|
3314 |
+
label="π Spending Analysis by Category",
|
3315 |
+
elem_classes="analytics-chart"
|
3316 |
+
)
|
3317 |
+
balance_chart = gr.Plot(
|
3318 |
+
label="π° Balance Trend Over Time",
|
3319 |
+
elem_classes="analytics-chart"
|
3320 |
+
)
|
3321 |
|
3322 |
+
# Enhanced Spending History Tab
|
3323 |
with gr.Tab("π Spending History"):
|
3324 |
+
gr.HTML("""
|
3325 |
+
<div class="info-card gradient-bg-3" style="color: white; text-align: center; padding: 2.5rem; margin-bottom: 2rem;">
|
3326 |
+
<h3 style="font-size: 1.8rem; margin-bottom: 1rem;">π Complete Transaction History</h3>
|
3327 |
+
<p style="font-size: 1.1rem; opacity: 0.9;">Review all your financial transactions with detailed information and balance tracking</p>
|
3328 |
+
</div>
|
3329 |
+
""")
|
3330 |
+
|
3331 |
spending_log_table = gr.Dataframe(
|
3332 |
+
headers=["Category", "Amount (PKR)", "Description", "Date", "Balance After (PKR)"],
|
3333 |
interactive=False,
|
3334 |
+
wrap=True,
|
3335 |
+
elem_classes="spending-history-table"
|
3336 |
)
|
3337 |
+
|
3338 |
+
gr.HTML("""
|
3339 |
+
<div class="info-card">
|
3340 |
+
<h3>π‘ Understanding Your Spending History</h3>
|
3341 |
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; margin-top: 1rem;">
|
3342 |
+
<div style="background: #f7fafc; padding: 1rem; border-radius: 8px; border-left: 3px solid #4299e1;">
|
3343 |
+
<h4 style="color: #2d3748; font-size: 1rem; margin-bottom: 0.5rem;">π Track Patterns</h4>
|
3344 |
+
<p style="color: #4a5568; font-size: 0.9rem;">Identify spending habits and trends over time</p>
|
3345 |
+
</div>
|
3346 |
+
<div style="background: #f7fafc; padding: 1rem; border-radius: 8px; border-left: 3px solid #48bb78;">
|
3347 |
+
<h4 style="color: #2d3748; font-size: 1rem; margin-bottom: 0.5rem;">π° Balance Tracking</h4>
|
3348 |
+
<p style="color: #4a5568; font-size: 0.9rem;">See how each transaction affected your balance</p>
|
3349 |
+
</div>
|
3350 |
+
<div style="background: #f7fafc; padding: 1rem; border-radius: 8px; border-left: 3px solid #ed8936;">
|
3351 |
+
<h4 style="color: #2d3748; font-size: 1rem; margin-bottom: 0.5rem;">π Category Analysis</h4>
|
3352 |
+
<p style="color: #4a5568; font-size: 0.9rem;">Understand where your money goes each month</p>
|
3353 |
+
</div>
|
3354 |
+
</div>
|
3355 |
+
</div>
|
3356 |
+
""")
|
3357 |
|
3358 |
+
# Enhanced Investment Portfolio Tab
|
3359 |
with gr.Tab("π Investment Portfolio"):
|
3360 |
+
gr.HTML("""
|
3361 |
+
<div class="info-card gradient-bg-4" style="color: white; text-align: center; padding: 2.5rem; margin-bottom: 2rem;">
|
3362 |
+
<h3 style="font-size: 1.8rem; margin-bottom: 1rem;">π Investment Portfolio Management</h3>
|
3363 |
+
<p style="font-size: 1.1rem; opacity: 0.9;">Track your investments and build long-term wealth with comprehensive portfolio monitoring</p>
|
3364 |
+
</div>
|
3365 |
+
""")
|
3366 |
+
|
3367 |
with gr.Row():
|
3368 |
+
with gr.Column(scale=1):
|
3369 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>β Add New Investment</h4>")
|
3370 |
+
|
3371 |
+
investment_type = gr.Dropdown(
|
3372 |
+
choices=INVESTMENT_TYPES,
|
3373 |
+
label="π’ Investment Type",
|
3374 |
+
info="Select the type of investment"
|
3375 |
+
)
|
3376 |
+
|
3377 |
+
investment_name = gr.Textbox(
|
3378 |
+
label="π Investment Name/Description",
|
3379 |
+
placeholder="e.g., Apple Stock, Bitcoin, Mutual Fund XYZ",
|
3380 |
+
info="Specific name or description of the investment"
|
3381 |
+
)
|
3382 |
+
|
3383 |
+
with gr.Row():
|
3384 |
+
investment_amount = gr.Number(
|
3385 |
+
label="π° Amount Invested (PKR)",
|
3386 |
+
minimum=1,
|
3387 |
+
step=1000,
|
3388 |
+
value=0,
|
3389 |
+
info="How much are you investing?"
|
3390 |
+
)
|
3391 |
+
|
3392 |
+
investment_notes = gr.Textbox(
|
3393 |
+
label="π Additional Notes",
|
3394 |
+
lines=3,
|
3395 |
+
placeholder="Investment strategy, expected returns, risk level, etc.",
|
3396 |
+
info="Optional: Add any additional information"
|
3397 |
+
)
|
3398 |
+
|
3399 |
+
add_investment_btn = gr.Button(
|
3400 |
+
"π Add to Portfolio",
|
3401 |
+
variant="primary",
|
3402 |
+
elem_classes="primary-btn",
|
3403 |
+
size="lg"
|
3404 |
+
)
|
3405 |
+
investment_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
3406 |
|
3407 |
+
with gr.Column(scale=1):
|
3408 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>πΌ Your Investment Portfolio</h4>")
|
3409 |
+
|
3410 |
investments_table = gr.Dataframe(
|
3411 |
+
headers=["Type", "Name", "Amount (PKR)", "Date Added", "Notes"],
|
3412 |
interactive=False,
|
3413 |
+
wrap=True,
|
3414 |
+
elem_classes="investments-table"
|
3415 |
)
|
3416 |
+
|
3417 |
+
gr.HTML("""
|
3418 |
+
<div class="info-card">
|
3419 |
+
<h3>π‘ Investment Tips</h3>
|
3420 |
+
<ul style="text-align: left; margin-left: 1rem; line-height: 1.8; color: #4a5568;">
|
3421 |
+
<li><strong>π― Diversify:</strong> Spread investments across different asset classes</li>
|
3422 |
+
<li><strong>π
Long-term Focus:</strong> Think in years, not months</li>
|
3423 |
+
<li><strong>π Regular Review:</strong> Monitor performance quarterly</li>
|
3424 |
+
<li><strong>π‘ Research First:</strong> Understand before you invest</li>
|
3425 |
+
<li><strong>βοΈ Risk Management:</strong> Never invest more than you can afford to lose</li>
|
3426 |
+
</ul>
|
3427 |
+
</div>
|
3428 |
+
""")
|
3429 |
+
|
3430 |
+
# Enhanced Family Finance Tab
|
3431 |
with gr.Tab("πͺ Family Finance"):
|
3432 |
+
gr.HTML("""
|
3433 |
+
<div class="info-card gradient-bg-1" style="color: white; text-align: center; padding: 2.5rem; margin-bottom: 2rem;">
|
3434 |
+
<h3 style="font-size: 1.8rem; margin-bottom: 1rem;">π¨βπ©βπ§βπ¦ Collaborative Family Finance</h3>
|
3435 |
+
<p style="font-size: 1.1rem; opacity: 0.9;">Create family groups to manage household budgets, shared expenses, and financial goals together</p>
|
3436 |
+
</div>
|
3437 |
+
""")
|
3438 |
+
|
3439 |
+
family_info = gr.Textbox(
|
3440 |
+
label="π₯ Current Family Group Status",
|
3441 |
+
interactive=False,
|
3442 |
+
elem_classes="family-status"
|
3443 |
+
)
|
3444 |
|
3445 |
with gr.Row():
|
3446 |
+
with gr.Column(scale=1):
|
3447 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>β Create New Family Group</h4>")
|
3448 |
+
|
3449 |
+
create_group_name = gr.Textbox(
|
3450 |
+
label="πͺ Family Group Name",
|
3451 |
+
placeholder="e.g., Smith Family Budget, Our Household",
|
3452 |
+
info="Choose a name that represents your family"
|
3453 |
+
)
|
3454 |
+
|
3455 |
+
create_group_btn = gr.Button(
|
3456 |
+
"Create Family Group",
|
3457 |
+
variant="primary",
|
3458 |
+
elem_classes="primary-btn",
|
3459 |
+
size="lg"
|
3460 |
+
)
|
3461 |
|
3462 |
+
with gr.Column(scale=1):
|
3463 |
+
gr.HTML("<h4 style='color: #2d3748; margin-bottom: 1rem;'>π Join Existing Family Group</h4>")
|
3464 |
+
|
3465 |
+
join_group_id = gr.Textbox(
|
3466 |
+
label="π Family Group ID",
|
3467 |
+
placeholder="FG-XXXX-XXXXXXXX",
|
3468 |
+
info="Enter the group ID shared by your family admin"
|
3469 |
+
)
|
3470 |
+
|
3471 |
+
join_group_btn = gr.Button(
|
3472 |
+
"Join Family Group",
|
3473 |
+
variant="secondary",
|
3474 |
+
elem_classes="secondary-btn",
|
3475 |
+
size="lg"
|
3476 |
+
)
|
3477 |
|
3478 |
+
family_status = gr.Textbox(label="Status", interactive=False, elem_classes="status-display")
|
3479 |
|
3480 |
+
gr.HTML("<h4 style='color: #2d3748; margin: 2rem 0 1rem 0;'>π₯ Family Group Members</h4>")
|
3481 |
family_members = gr.Dataframe(
|
3482 |
+
headers=["Phone Number", "Member Name"],
|
3483 |
interactive=False,
|
3484 |
+
wrap=True,
|
3485 |
+
elem_classes="family-members-table"
|
3486 |
)
|
3487 |
+
|
3488 |
+
gr.HTML("""
|
3489 |
+
<div class="info-card">
|
3490 |
+
<h3>π Family Finance Benefits</h3>
|
3491 |
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; margin-top: 1rem;">
|
3492 |
+
<div style="background: #e6fffa; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #38b2ac;">
|
3493 |
+
<h4 style="color: #2d3748; margin-bottom: 0.5rem;">π€ Shared Responsibility</h4>
|
3494 |
+
<p style="color: #4a5568; font-size: 0.9rem;">All family members can contribute to expense tracking and budget management</p>
|
3495 |
+
</div>
|
3496 |
+
<div style="background: #fef5e7; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #ed8936;">
|
3497 |
+
<h4 style="color: #2d3748; margin-bottom: 0.5rem;">ποΈ Transparency</h4>
|
3498 |
+
<p style="color: #4a5568; font-size: 0.9rem;">Everyone can see family spending patterns and financial goals</p>
|
3499 |
+
</div>
|
3500 |
+
<div style="background: #e6ffed; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #48bb78;">
|
3501 |
+
<h4 style="color: #2d3748; margin-bottom: 0.5rem;">π― Collective Goals</h4>
|
3502 |
+
<p style="color: #4a5568; font-size: 0.9rem;">Work together towards shared financial objectives and savings targets</p>
|
3503 |
+
</div>
|
3504 |
+
</div>
|
3505 |
+
</div>
|
3506 |
+
""")
|
3507 |
|
3508 |
+
# Enhanced Sign Out Section
|
3509 |
with gr.Row():
|
3510 |
+
with gr.Column(scale=4):
|
3511 |
+
gr.HTML("") # Spacer
|
3512 |
with gr.Column(scale=1):
|
3513 |
+
sign_out_btn = gr.Button(
|
3514 |
+
"πͺ Sign Out",
|
3515 |
+
variant="stop",
|
3516 |
+
elem_classes="secondary-btn",
|
3517 |
+
size="lg"
|
3518 |
+
)
|
3519 |
|
3520 |
# ===== EVENT HANDLERS =====
|
3521 |
|
|
|
3643 |
logger.info(" 4. Use the same phone number for both WhatsApp activation and app registration")
|
3644 |
logger.info(" 5. Phone number format: +92XXXXXXXXXX (Pakistan format)")
|
3645 |
logger.info("")
|
3646 |
+
logger.info("β
All enhancements implemented:")
|
3647 |
+
logger.info(" β
Fixed button sizing issues - all buttons now have equal dimensions")
|
3648 |
+
logger.info(" β
Fixed landing page size consistency - maintains proper dimensions")
|
3649 |
+
logger.info(" β
Enhanced dashboard UI/UX with modern design patterns")
|
3650 |
+
logger.info(" β
Improved responsive design for all screen sizes")
|
3651 |
+
logger.info(" β
Enhanced visual hierarchy and information architecture")
|
3652 |
+
logger.info(" β
Added comprehensive CSS variables and theming system")
|
3653 |
+
logger.info(" β
Implemented advanced animations and micro-interactions")
|
3654 |
+
logger.info(" β
Enhanced accessibility and usability features")
|
3655 |
+
logger.info(" β
Improved form layouts and data presentation")
|
3656 |
+
logger.info(" β
Added contextual help and guidance elements")
|
3657 |
+
logger.info(" β
Enhanced error handling and user feedback")
|
3658 |
+
logger.info("")
|
3659 |
+
logger.info("π¨ UI/UX Improvements:")
|
3660 |
+
logger.info(" β’ Consistent button sizing across all pages")
|
3661 |
+
logger.info(" β’ Fixed landing page dimension preservation")
|
3662 |
+
logger.info(" β’ Enhanced color scheme with CSS variables")
|
3663 |
+
logger.info(" β’ Improved spacing and typography")
|
3664 |
+
logger.info(" β’ Better visual feedback for user actions")
|
3665 |
+
logger.info(" β’ Enhanced mobile responsiveness")
|
3666 |
+
logger.info(" β’ Modern card-based layout system")
|
3667 |
+
logger.info(" β’ Professional gradient backgrounds")
|
3668 |
+
logger.info(" β’ Improved table and data visualization")
|
3669 |
+
logger.info(" β’ Enhanced form usability and validation")
|
3670 |
logger.info("")
|
3671 |
|
3672 |
try:
|
|
|
3676 |
share=False,
|
3677 |
show_error=True,
|
3678 |
favicon_path=None,
|
3679 |
+
ssl_verify=False,
|
3680 |
+
show_tips=True,
|
3681 |
+
enable_queue=True,
|
3682 |
+
max_threads=10
|
3683 |
)
|
3684 |
except Exception as e:
|
3685 |
logger.error(f"β Failed to launch application: {e}")
|