Devavrat28 commited on
Commit
1b9d3b8
Β·
verified Β·
1 Parent(s): f95647d

Added features to the app.

Browse files
Files changed (1) hide show
  1. app.py +250 -68
app.py CHANGED
@@ -1,28 +1,40 @@
1
  #Gradio app
2
  # app.py
3
- # app.py - Original approach with profile object
4
- # app.py
5
  import gradio as gr
6
  import requests
7
  import json
 
 
 
8
 
 
9
  MODAL_URL = "https://devsam2898--personal-investment-strategist-optimized-web.modal.run/strategy"
 
 
10
 
11
- def get_investment_strategy(age_group, income, expenses, risk_profile, goal, timeframe):
12
- """
13
- Get investment strategy from Modal backend
14
- """
15
  # Input validation
16
- if not all([age_group, income, expenses, risk_profile, goal, timeframe]):
17
  return "❌ Please fill in all fields to get a personalized strategy."
18
 
19
- # Convert income and expenses to numbers if they're strings
20
  try:
21
- income_val = float(income.replace('$', '').replace(',', '')) if isinstance(income, str) else float(income)
22
- expenses_val = float(expenses.replace('$', '').replace(',', '')) if isinstance(expenses, str) else float(expenses)
23
  except ValueError:
24
  return "❌ Please enter valid numbers for income and expenses."
25
 
 
 
 
 
 
 
 
 
26
  payload = {
27
  "profile": {
28
  "age_group": age_group,
@@ -30,118 +42,288 @@ def get_investment_strategy(age_group, income, expenses, risk_profile, goal, tim
30
  "expenses": expenses_val,
31
  "risk_profile": risk_profile,
32
  "goal": goal,
33
- "timeframe": timeframe
 
34
  }
35
  }
36
 
37
  try:
38
- print(f"Sending request to: {MODAL_URL}")
39
- print(f"Payload: {json.dumps(payload, indent=2)}")
40
 
41
- response = requests.post(
42
- MODAL_URL,
43
- json=payload,
44
- headers={
45
- 'Content-Type': 'application/json',
46
- 'Accept': 'application/json'
47
- },
48
- timeout=30 # Add timeout
49
- )
50
 
51
- print(f"Response status: {response.status_code}")
52
- print(f"Response headers: {dict(response.headers)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- if response.status_code == 200:
55
- result = response.json()
56
- strategy = result.get("strategy", "No strategy returned.")
57
- return f"## πŸ“Š Your Personalized Investment Strategy\n\n{strategy}"
58
- else:
59
- error_msg = f"❌ **Error {response.status_code}**\n\n"
 
 
 
 
 
 
 
60
  try:
61
- error_detail = response.json()
62
- error_msg += f"Details: {error_detail}"
63
- except:
64
- error_msg += f"Response: {response.text}"
65
- return error_msg
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
- except requests.exceptions.Timeout:
68
- return "❌ **Request Timeout**: The service is taking too long to respond. Please try again."
69
- except requests.exceptions.ConnectionError:
70
- return "❌ **Connection Error**: Unable to connect to the backend service. Please check if the Modal service is running."
71
- except requests.exceptions.RequestException as e:
72
- return f"❌ **Network Error**: {str(e)}"
73
  except Exception as e:
74
- return f"❌ **Unexpected Error**: {str(e)}"
 
 
 
 
75
 
76
- # Test function to verify the function works
77
- def test_function():
78
- return "βœ… Function is working correctly!"
 
79
 
80
- # Create the interface
81
- with gr.Blocks(theme="soft", title="πŸ“ˆ Personal Finance Strategist") as interface:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  gr.Markdown(
83
  """
84
  # πŸ“ˆ Personal Finance Strategist
85
- **Powered by LlamaIndex + Nebius Qwen3**
 
 
86
 
87
- Get personalized investment strategies based on your life stage and financial goals.
88
  """
89
  )
90
 
91
  with gr.Row():
92
  with gr.Column(scale=1):
 
93
  age_group = gr.Dropdown(
94
  choices=["20s", "30s", "40s", "50s+"],
95
  label="Age Group",
96
- value="30s"
 
 
 
 
 
 
 
 
 
 
 
97
  )
98
- income = gr.Textbox(
 
 
99
  label="Monthly Income ($)",
100
- value="6000",
101
- placeholder="e.g., 6000"
 
102
  )
103
- expenses = gr.Textbox(
104
  label="Monthly Expenses ($)",
105
- value="4000",
106
- placeholder="e.g., 4000"
 
107
  )
108
 
109
  with gr.Column(scale=1):
 
110
  risk_profile = gr.Radio(
111
  choices=["Conservative", "Moderate", "Aggressive"],
112
  label="Risk Tolerance",
113
- value="Moderate"
 
114
  )
115
  goal = gr.Textbox(
116
  label="Financial Goal",
117
- placeholder="e.g., buy a house, retirement, emergency fund"
 
118
  )
119
  timeframe = gr.Textbox(
120
- label="Timeframe",
121
- placeholder="e.g., 5 years, 10 years"
 
122
  )
123
 
 
 
124
  with gr.Row():
125
- submit_btn = gr.Button("Get Investment Strategy", variant="primary")
126
- test_btn = gr.Button("Test Connection", variant="secondary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- output = gr.Markdown(label="Investment Strategy")
 
 
 
129
 
130
  # Event handlers
131
  submit_btn.click(
132
  fn=get_investment_strategy,
133
- inputs=[age_group, income, expenses, risk_profile, goal, timeframe],
134
- outputs=output
 
135
  )
136
 
137
  test_btn.click(
138
- fn=test_function,
139
- outputs=output
 
140
  )
141
 
142
  if __name__ == "__main__":
143
  interface.launch(
144
  server_name="0.0.0.0",
145
  server_port=7860,
146
- share=False
 
 
147
  )
 
1
  #Gradio app
2
  # app.py
3
+ # app.py - Optimized with better timeout handling
 
4
  import gradio as gr
5
  import requests
6
  import json
7
+ import asyncio
8
+ import aiohttp
9
+ from typing import Optional
10
 
11
+ # Update this to your new optimized Modal URL
12
  MODAL_URL = "https://devsam2898--personal-investment-strategist-optimized-web.modal.run/strategy"
13
+ HEALTH_URL = "https://devsam2898--personal-investment-strategist-optimized-web.modal.run/health"
14
+ TEST_URL = "https://devsam2898--personal-investment-strategist-optimized-web.modal.run/test"
15
 
16
+ async def get_investment_strategy_async(age_group, income, expenses, risk_profile, goal, timeframe, country):
17
+ """Async version with better timeout handling"""
18
+
 
19
  # Input validation
20
+ if not all([age_group, income, expenses, risk_profile, goal, timeframe, country]):
21
  return "❌ Please fill in all fields to get a personalized strategy."
22
 
23
+ # Convert income and expenses to numbers
24
  try:
25
+ income_val = float(str(income).replace('$', '').replace(',', '')) if income else 0
26
+ expenses_val = float(str(expenses).replace('$', '').replace(',', '')) if expenses else 0
27
  except ValueError:
28
  return "❌ Please enter valid numbers for income and expenses."
29
 
30
+ # Validate financial logic
31
+ if income_val <= 0:
32
+ return "❌ Income must be greater than 0."
33
+ if expenses_val < 0:
34
+ return "❌ Expenses cannot be negative."
35
+ if expenses_val >= income_val:
36
+ return "⚠️ **Warning**: Your expenses are equal to or exceed your income. Consider budgeting advice before investing."
37
+
38
  payload = {
39
  "profile": {
40
  "age_group": age_group,
 
42
  "expenses": expenses_val,
43
  "risk_profile": risk_profile,
44
  "goal": goal,
45
+ "timeframe": timeframe,
46
+ "country": country
47
  }
48
  }
49
 
50
  try:
51
+ print(f"πŸš€ Sending request to: {MODAL_URL}")
 
52
 
53
+ # Use aiohttp for better async handling
54
+ timeout = aiohttp.ClientTimeout(total=150) # 2.5 minute timeout
 
 
 
 
 
 
 
55
 
56
+ async with aiohttp.ClientSession(timeout=timeout) as session:
57
+ async with session.post(
58
+ MODAL_URL,
59
+ json=payload,
60
+ headers={
61
+ 'Content-Type': 'application/json',
62
+ 'Accept': 'application/json'
63
+ }
64
+ ) as response:
65
+
66
+ print(f"πŸ“Š Response status: {response.status}")
67
+
68
+ if response.status == 200:
69
+ result = await response.json()
70
+ strategy = result.get("strategy", "No strategy returned.")
71
+ status = result.get("status", "unknown")
72
+
73
+ # Add status indicator
74
+ if status == "basic":
75
+ prefix = "## πŸ“Š Your Investment Strategy (Rule-Based)\n*AI service was unavailable, using optimized rule-based strategy*\n\n"
76
+ else:
77
+ prefix = "## πŸ“Š Your Personalized Investment Strategy\n*Powered by AI*\n\n"
78
+
79
+ return f"{prefix}{strategy}"
80
+ else:
81
+ error_text = await response.text()
82
+ return f"❌ **Service Error ({response.status})**\n\nThe backend service returned an error. Please try again in a moment.\n\nDetails: {error_text[:200]}..."
83
+
84
+ except asyncio.TimeoutError:
85
+ return """⏱️ **Request Timeout**
86
+
87
+ The AI service is taking longer than expected. This could be due to:
88
+ - High server load
89
+ - Cold start (first request after idle period)
90
+ - Network connectivity issues
91
+
92
+ **What to try:**
93
+ 1. Wait 30 seconds and try again
94
+ 2. Simplify your goal description
95
+ 3. Check if the service is healthy using the 'Test Service' button"""
96
+
97
+ except aiohttp.ClientError as e:
98
+ return f"""πŸ”Œ **Connection Error**
99
+
100
+ Unable to connect to the backend service.
101
+
102
+ **Possible causes:**
103
+ - Service is starting up (cold start)
104
+ - Network connectivity issues
105
+ - Service is temporarily down
106
+
107
+ **What to try:**
108
+ 1. Wait 1-2 minutes and try again
109
+ 2. Check service health with 'Test Service' button
110
+ 3. Refresh the page
111
+
112
+ *Technical details: {str(e)}*"""
113
+
114
+ except Exception as e:
115
+ return f"""❌ **Unexpected Error**
116
+
117
+ An unexpected error occurred: {str(e)}
118
+
119
+ Please try again or contact support if the issue persists."""
120
+
121
+ def get_investment_strategy(age_group, income, expenses, risk_profile, goal, timeframe, country):
122
+ """Sync wrapper for async function"""
123
+ try:
124
+ loop = asyncio.new_event_loop()
125
+ asyncio.set_event_loop(loop)
126
+ result = loop.run_until_complete(
127
+ get_investment_strategy_async(age_group, income, expenses, risk_profile, goal, timeframe, country)
128
+ )
129
+ loop.close()
130
+ return result
131
+ except Exception as e:
132
+ return f"❌ **Error**: {str(e)}"
133
+
134
+ async def test_service_async():
135
+ """Test service connectivity"""
136
+ try:
137
+ timeout = aiohttp.ClientTimeout(total=30)
138
 
139
+ async with aiohttp.ClientSession(timeout=timeout) as session:
140
+ # Test health endpoint first
141
+ try:
142
+ async with session.get(HEALTH_URL) as response:
143
+ if response.status == 200:
144
+ health_data = await response.json()
145
+ health_status = f"βœ… Service is healthy\n- Status: {health_data.get('status')}\n- Timestamp: {health_data.get('timestamp')}"
146
+ else:
147
+ health_status = f"⚠️ Health check returned status {response.status}"
148
+ except Exception as e:
149
+ health_status = f"❌ Health check failed: {str(e)}"
150
+
151
+ # Test strategy endpoint with sample data
152
  try:
153
+ async with session.get(TEST_URL) as response:
154
+ if response.status == 200:
155
+ test_data = await response.json()
156
+ test_status = f"βœ… Test endpoint working\n- Result: {test_data.get('test_result')}"
157
+ else:
158
+ test_status = f"⚠️ Test endpoint returned status {response.status}"
159
+ except Exception as e:
160
+ test_status = f"❌ Test endpoint failed: {str(e)}"
161
+
162
+ return f"""## πŸ” Service Status Check
163
+
164
+ **Health Check:**
165
+ {health_status}
166
+
167
+ **Functionality Test:**
168
+ {test_status}
169
+
170
+ **Service URL:** {MODAL_URL}
171
+
172
+ *Last checked: {asyncio.get_event_loop().time()}*"""
173
 
 
 
 
 
 
 
174
  except Exception as e:
175
+ return f"""❌ **Service Test Failed**
176
+
177
+ Unable to connect to the service.
178
+
179
+ Error: {str(e)}
180
 
181
+ **Troubleshooting:**
182
+ 1. Check if the Modal deployment is running
183
+ 2. Verify the service URL is correct
184
+ 3. Check network connectivity"""
185
 
186
+ def test_service():
187
+ """Sync wrapper for service test"""
188
+ try:
189
+ loop = asyncio.new_event_loop()
190
+ asyncio.set_event_loop(loop)
191
+ result = loop.run_until_complete(test_service_async())
192
+ loop.close()
193
+ return result
194
+ except Exception as e:
195
+ return f"❌ **Test Error**: {str(e)}"
196
+
197
+ # Create the interface with better UX
198
+ with gr.Blocks(
199
+ theme=gr.themes.Soft(primary_hue="blue", secondary_hue="slate"),
200
+ title="πŸ“ˆ Personal Finance Strategist",
201
+ css="""
202
+ .gradio-container {
203
+ max-width: 1200px !important;
204
+ }
205
+ .status-box {
206
+ padding: 10px;
207
+ border-radius: 8px;
208
+ margin: 10px 0;
209
+ }
210
+ """
211
+ ) as interface:
212
+
213
  gr.Markdown(
214
  """
215
  # πŸ“ˆ Personal Finance Strategist
216
+ **AI-Powered Investment Strategy Generator**
217
+
218
+ Get personalized investment recommendations based on your financial profile and goals.
219
 
220
+ ---
221
  """
222
  )
223
 
224
  with gr.Row():
225
  with gr.Column(scale=1):
226
+ gr.Markdown("### πŸ‘€ Personal Information")
227
  age_group = gr.Dropdown(
228
  choices=["20s", "30s", "40s", "50s+"],
229
  label="Age Group",
230
+ value="30s",
231
+ info="Select your current age range"
232
+ )
233
+
234
+ country = gr.Dropdown(
235
+ choices=[
236
+ "United States", "Canada", "United Kingdom",
237
+ "Germany", "France", "Italy", "Japan", "India"
238
+ ],
239
+ label="Country of Residence",
240
+ value="United States",
241
+ info="Your tax residence country"
242
  )
243
+
244
+ gr.Markdown("### πŸ’° Financial Information")
245
+ income = gr.Number(
246
  label="Monthly Income ($)",
247
+ value=6000,
248
+ minimum=0,
249
+ info="Your total monthly income before taxes"
250
  )
251
+ expenses = gr.Number(
252
  label="Monthly Expenses ($)",
253
+ value=4000,
254
+ minimum=0,
255
+ info="Your total monthly expenses"
256
  )
257
 
258
  with gr.Column(scale=1):
259
+ gr.Markdown("### 🎯 Investment Preferences")
260
  risk_profile = gr.Radio(
261
  choices=["Conservative", "Moderate", "Aggressive"],
262
  label="Risk Tolerance",
263
+ value="Moderate",
264
+ info="How comfortable are you with investment risk?"
265
  )
266
  goal = gr.Textbox(
267
  label="Financial Goal",
268
+ placeholder="e.g., buy a house, retirement, emergency fund, child's education",
269
+ info="What are you saving/investing for?"
270
  )
271
  timeframe = gr.Textbox(
272
+ label="Investment Timeframe",
273
+ placeholder="e.g., 5 years, 10 years, until retirement",
274
+ info="How long do you plan to invest?"
275
  )
276
 
277
+ gr.Markdown("---")
278
+
279
  with gr.Row():
280
+ submit_btn = gr.Button(
281
+ "πŸš€ Generate Investment Strategy",
282
+ variant="primary",
283
+ size="lg"
284
+ )
285
+ test_btn = gr.Button(
286
+ "πŸ” Test Service",
287
+ variant="secondary",
288
+ size="lg"
289
+ )
290
+
291
+ with gr.Row():
292
+ gr.Markdown(
293
+ """
294
+ **πŸ’‘ Tips for best results:**
295
+ - Be specific about your financial goal
296
+ - Include realistic timeframes
297
+ - Consider your actual risk tolerance
298
+ - Make sure your income > expenses for meaningful investing
299
+ - Country selection affects tax-advantaged account recommendations
300
+ """
301
+ )
302
 
303
+ output = gr.Markdown(
304
+ label="Investment Strategy",
305
+ value="Click 'Generate Investment Strategy' to get your personalized recommendations!"
306
+ )
307
 
308
  # Event handlers
309
  submit_btn.click(
310
  fn=get_investment_strategy,
311
+ inputs=[age_group, income, expenses, risk_profile, goal, timeframe, country],
312
+ outputs=output,
313
+ show_progress=True
314
  )
315
 
316
  test_btn.click(
317
+ fn=test_service,
318
+ outputs=output,
319
+ show_progress=True
320
  )
321
 
322
  if __name__ == "__main__":
323
  interface.launch(
324
  server_name="0.0.0.0",
325
  server_port=7860,
326
+ share=False,
327
+ show_error=True,
328
+ debug=True
329
  )