LogicGoInfotechSpaces commited on
Commit
847392c
·
0 Parent(s):

Initial smart budget API

Browse files
.dockerignore ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__
2
+ *.pyc
3
+ *.pyo
4
+ *.pyd
5
+ .Python
6
+ env/
7
+ venv/
8
+ .venv
9
+ pip-log.txt
10
+ pip-delete-this-directory.txt
11
+ .tox/
12
+ .coverage
13
+ .coverage.*
14
+ .cache
15
+ nosetests.xml
16
+ coverage.xml
17
+ *.cover
18
+ *.log
19
+ .git
20
+ .gitignore
21
+ .mypy_cache
22
+ .pytest_cache
23
+ .hypothesis
24
+ .DS_Store
25
+ *.swp
26
+ *.swo
27
+ *~
28
+
.gitignore ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ build/
7
+ develop-eggs/
8
+ dist/
9
+ downloads/
10
+ eggs/
11
+ .eggs/
12
+ lib/
13
+ lib64/
14
+ parts/
15
+ sdist/
16
+ var/
17
+ wheels/
18
+ *.egg-info/
19
+ .installed.cfg
20
+ *.egg
21
+ MANIFEST
22
+
23
+ # Virtual environments
24
+ venv/
25
+ ENV/
26
+ env/
27
+ .venv
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # Environment variables
37
+ .env
38
+ .env.local
39
+
40
+ # Logs
41
+ *.log
42
+
43
+ # OS
44
+ .DS_Store
45
+ Thumbs.db
46
+
API_DOCUMENTATION.md ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # API Documentation
2
+
3
+ This is a **REST API** built with FastAPI. It provides endpoints for expense tracking and smart budget recommendations.
4
+
5
+ ## Base URL
6
+
7
+ - **Local**: `http://localhost:8000`
8
+ - **Hugging Face**: `https://your-username-your-space.hf.space`
9
+
10
+ ## Interactive Documentation
11
+
12
+ FastAPI automatically generates interactive API documentation:
13
+
14
+ - **Swagger UI**: `http://your-url/docs` - Interactive API explorer
15
+ - **ReDoc**: `http://your-url/redoc` - Alternative documentation format
16
+
17
+ ## API Endpoints
18
+
19
+ ### 1. Health Check
20
+
21
+ **GET** `/health`
22
+
23
+ Check if the API and database are running.
24
+
25
+ **Response:**
26
+ ```json
27
+ {
28
+ "status": "healthy",
29
+ "database": "connected"
30
+ }
31
+ ```
32
+
33
+ **Example:**
34
+ ```bash
35
+ curl http://localhost:8000/health
36
+ ```
37
+
38
+ ---
39
+
40
+ ### 2. Root Endpoint
41
+
42
+ **GET** `/`
43
+
44
+ Get API status.
45
+
46
+ **Response:**
47
+ ```json
48
+ {
49
+ "message": "Smart Budget Recommendation API",
50
+ "status": "running"
51
+ }
52
+ ```
53
+
54
+ ---
55
+
56
+ ### 3. Create Expense
57
+
58
+ **POST** `/expenses`
59
+
60
+ Create a new expense record.
61
+
62
+ **Request Body:**
63
+ ```json
64
+ {
65
+ "user_id": "user123",
66
+ "amount": 3800,
67
+ "category": "Groceries",
68
+ "description": "Monthly groceries",
69
+ "date": "2024-01-15T00:00:00",
70
+ "type": "expense"
71
+ }
72
+ ```
73
+
74
+ **Response:**
75
+ ```json
76
+ {
77
+ "id": "507f1f77bcf86cd799439011",
78
+ "message": "Expense created successfully"
79
+ }
80
+ ```
81
+
82
+ **Example:**
83
+ ```bash
84
+ curl -X POST "http://localhost:8000/expenses" \
85
+ -H "Content-Type: application/json" \
86
+ -d '{
87
+ "user_id": "user123",
88
+ "amount": 3800,
89
+ "category": "Groceries",
90
+ "description": "Monthly groceries",
91
+ "date": "2024-01-15T00:00:00",
92
+ "type": "expense"
93
+ }'
94
+ ```
95
+
96
+ ---
97
+
98
+ ### 4. Get Expenses
99
+
100
+ **GET** `/expenses?user_id={user_id}&limit={limit}`
101
+
102
+ Get expenses for a specific user.
103
+
104
+ **Query Parameters:**
105
+ - `user_id` (required): User identifier
106
+ - `limit` (optional): Maximum number of expenses to return (default: 100)
107
+
108
+ **Response:**
109
+ ```json
110
+ [
111
+ {
112
+ "id": "507f1f77bcf86cd799439011",
113
+ "user_id": "user123",
114
+ "amount": 3800,
115
+ "category": "Groceries",
116
+ "description": "Monthly groceries",
117
+ "date": "2024-01-15T00:00:00",
118
+ "type": "expense"
119
+ }
120
+ ]
121
+ ```
122
+
123
+ **Example:**
124
+ ```bash
125
+ curl "http://localhost:8000/expenses?user_id=user123&limit=10"
126
+ ```
127
+
128
+ ---
129
+
130
+ ### 5. Create Budget
131
+
132
+ **POST** `/budgets`
133
+
134
+ Create a new budget.
135
+
136
+ **Request Body:**
137
+ ```json
138
+ {
139
+ "user_id": "user123",
140
+ "category": "Groceries",
141
+ "amount": 4000,
142
+ "period": "monthly",
143
+ "start_date": "2024-02-01T00:00:00",
144
+ "end_date": "2024-02-29T00:00:00"
145
+ }
146
+ ```
147
+
148
+ **Response:**
149
+ ```json
150
+ {
151
+ "id": "507f1f77bcf86cd799439012",
152
+ "message": "Budget created successfully"
153
+ }
154
+ ```
155
+
156
+ ---
157
+
158
+ ### 6. Get Budgets
159
+
160
+ **GET** `/budgets?user_id={user_id}`
161
+
162
+ Get budgets for a specific user.
163
+
164
+ **Query Parameters:**
165
+ - `user_id` (required): User identifier
166
+
167
+ **Response:**
168
+ ```json
169
+ [
170
+ {
171
+ "id": "507f1f77bcf86cd799439012",
172
+ "user_id": "user123",
173
+ "category": "Groceries",
174
+ "amount": 4000,
175
+ "period": "monthly",
176
+ "start_date": "2024-02-01T00:00:00",
177
+ "end_date": "2024-02-29T00:00:00"
178
+ }
179
+ ]
180
+ ```
181
+
182
+ ---
183
+
184
+ ### 7. Get Smart Budget Recommendations ⭐
185
+
186
+ **GET** `/recommendations/{user_id}?month={month}&year={year}`
187
+
188
+ Get personalized budget recommendations based on past spending behavior.
189
+
190
+ **Path Parameters:**
191
+ - `user_id` (required): User identifier
192
+
193
+ **Query Parameters:**
194
+ - `month` (optional): Target month (1-12). Defaults to next month if not provided
195
+ - `year` (optional): Target year. Defaults to next year if not provided
196
+
197
+ **Response:**
198
+ ```json
199
+ [
200
+ {
201
+ "category": "Groceries",
202
+ "average_expense": 3800.0,
203
+ "recommended_budget": 4000.0,
204
+ "reason": "Your average monthly grocery expense is Rs.3,800. We suggest setting your budget to Rs.4,000 for next month (includes a 5% buffer for variability).",
205
+ "confidence": 0.85
206
+ },
207
+ {
208
+ "category": "Transport",
209
+ "average_expense": 2100.0,
210
+ "recommended_budget": 2200.0,
211
+ "reason": "Your average monthly transport expense is Rs.2,100. We suggest setting your budget to Rs.2,200 for next month (includes a 5% buffer for variability).",
212
+ "confidence": 0.75
213
+ }
214
+ ]
215
+ ```
216
+
217
+ **Example:**
218
+ ```bash
219
+ # Get recommendations for next month (default)
220
+ curl "http://localhost:8000/recommendations/user123"
221
+
222
+ # Get recommendations for specific month
223
+ curl "http://localhost:8000/recommendations/user123?month=3&year=2024"
224
+ ```
225
+
226
+ **How it works:**
227
+ - Analyzes expenses from the past 6 months
228
+ - Calculates average monthly spending per category
229
+ - Adds a 5-10% buffer based on spending variability
230
+ - Returns recommendations sorted by average expense (highest first)
231
+
232
+ ---
233
+
234
+ ### 8. Get Category Expenses
235
+
236
+ **GET** `/category-expenses/{user_id}?months={months}`
237
+
238
+ Get average expenses by category for the past N months.
239
+
240
+ **Path Parameters:**
241
+ - `user_id` (required): User identifier
242
+
243
+ **Query Parameters:**
244
+ - `months` (optional): Number of months to analyze (default: 3)
245
+
246
+ **Response:**
247
+ ```json
248
+ [
249
+ {
250
+ "category": "Groceries",
251
+ "average_monthly_expense": 3800.0,
252
+ "total_expenses": 12,
253
+ "months_analyzed": 3
254
+ },
255
+ {
256
+ "category": "Transport",
257
+ "average_monthly_expense": 2100.0,
258
+ "total_expenses": 6,
259
+ "months_analyzed": 3
260
+ }
261
+ ]
262
+ ```
263
+
264
+ **Example:**
265
+ ```bash
266
+ curl "http://localhost:8000/category-expenses/user123?months=6"
267
+ ```
268
+
269
+ ---
270
+
271
+ ## Using the API with Python
272
+
273
+ ```python
274
+ import requests
275
+
276
+ BASE_URL = "http://localhost:8000"
277
+
278
+ # Create an expense
279
+ expense = {
280
+ "user_id": "user123",
281
+ "amount": 3800,
282
+ "category": "Groceries",
283
+ "description": "Monthly groceries",
284
+ "date": "2024-01-15T00:00:00",
285
+ "type": "expense"
286
+ }
287
+ response = requests.post(f"{BASE_URL}/expenses", json=expense)
288
+ print(response.json())
289
+
290
+ # Get recommendations
291
+ response = requests.get(f"{BASE_URL}/recommendations/user123")
292
+ recommendations = response.json()
293
+ for rec in recommendations:
294
+ print(f"{rec['category']}: {rec['recommended_budget']}")
295
+ print(f"Reason: {rec['reason']}")
296
+ ```
297
+
298
+ ## Using the API with JavaScript/Fetch
299
+
300
+ ```javascript
301
+ const BASE_URL = "http://localhost:8000";
302
+
303
+ // Create an expense
304
+ const expense = {
305
+ user_id: "user123",
306
+ amount: 3800,
307
+ category: "Groceries",
308
+ description: "Monthly groceries",
309
+ date: "2024-01-15T00:00:00",
310
+ type: "expense"
311
+ };
312
+
313
+ fetch(`${BASE_URL}/expenses`, {
314
+ method: "POST",
315
+ headers: { "Content-Type": "application/json" },
316
+ body: JSON.stringify(expense)
317
+ })
318
+ .then(res => res.json())
319
+ .then(data => console.log(data));
320
+
321
+ // Get recommendations
322
+ fetch(`${BASE_URL}/recommendations/user123`)
323
+ .then(res => res.json())
324
+ .then(recommendations => {
325
+ recommendations.forEach(rec => {
326
+ console.log(`${rec.category}: ${rec.recommended_budget}`);
327
+ console.log(`Reason: ${rec.reason}`);
328
+ });
329
+ });
330
+ ```
331
+
332
+ ## Error Responses
333
+
334
+ The API returns standard HTTP status codes:
335
+
336
+ - `200 OK` - Request successful
337
+ - `400 Bad Request` - Invalid request data
338
+ - `422 Unprocessable Entity` - Validation error
339
+ - `500 Internal Server Error` - Server error
340
+
341
+ Error response format:
342
+ ```json
343
+ {
344
+ "detail": "Error message description"
345
+ }
346
+ ```
347
+
348
+ ## CORS
349
+
350
+ The API has CORS enabled, allowing requests from any origin. This makes it easy to integrate with frontend applications.
351
+
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ gcc \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ # Copy requirements first for better caching
11
+ COPY requirements.txt .
12
+
13
+ # Install Python dependencies
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Copy application code
17
+ COPY app/ ./app/
18
+
19
+ # Expose port
20
+ EXPOSE 8000
21
+
22
+ # Set environment variables
23
+ ENV PYTHONUNBUFFERED=1
24
+
25
+ # Run the application
26
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
27
+
HUGGINGFACE_DEPLOYMENT.md ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Deployment Guide
2
+
3
+ This guide will help you deploy the Smart Budget Recommendation API to Hugging Face Spaces.
4
+
5
+ ## Prerequisites
6
+
7
+ 1. A Hugging Face account (sign up at https://huggingface.co)
8
+ 2. MongoDB connection string ready
9
+ 3. Git installed (optional, you can also use the web interface)
10
+
11
+ ## Step-by-Step Deployment
12
+
13
+ ### Step 1: Create a New Space
14
+
15
+ 1. Go to https://huggingface.co/spaces
16
+ 2. Click "Create new Space"
17
+ 3. Fill in the details:
18
+ - **Space name**: `smart-budget-recommendation` (or your preferred name)
19
+ - **SDK**: Select **Docker**
20
+ - **Visibility**: Choose Public or Private
21
+ 4. Click "Create Space"
22
+
23
+ ### Step 2: Add MongoDB URI as Secret
24
+
25
+ 1. In your Space, go to **Settings** (gear icon)
26
+ 2. Navigate to **Variables and secrets** section
27
+ 3. Click **New secret**
28
+ 4. Add:
29
+ - **Name**: `MONGODB_URI`
30
+ - **Value**: `mongodb://expenseuser:Kem_6o%3F%[email protected]:27017/expense?authSource=admin`
31
+ 5. Click **Add secret**
32
+
33
+ ### Step 3: Upload Files
34
+
35
+ You can upload files in two ways:
36
+
37
+ #### Option A: Using Git (Recommended)
38
+
39
+ 1. Clone your Space repository:
40
+ ```bash
41
+ git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
42
+ cd YOUR_SPACE_NAME
43
+ ```
44
+
45
+ 2. Copy all files from this project:
46
+ - `app/` directory (all Python files)
47
+ - `Dockerfile`
48
+ - `requirements.txt`
49
+ - `.dockerignore`
50
+ - `README.md` (optional)
51
+
52
+ 3. Commit and push:
53
+ ```bash
54
+ git add .
55
+ git commit -m "Initial deployment"
56
+ git push
57
+ ```
58
+
59
+ #### Option B: Using Web Interface
60
+
61
+ 1. In your Space, click **Files and versions** tab
62
+ 2. Click **Add file** → **Upload files**
63
+ 3. Upload all files:
64
+ - All files from `app/` directory
65
+ - `Dockerfile`
66
+ - `requirements.txt`
67
+ - `.dockerignore`
68
+
69
+ ### Step 4: Wait for Build
70
+
71
+ 1. Hugging Face will automatically detect the `Dockerfile` and start building
72
+ 2. You can monitor the build progress in the **Logs** tab
73
+ 3. The build typically takes 2-5 minutes
74
+
75
+ ### Step 5: Verify Deployment
76
+
77
+ Once the build completes:
78
+
79
+ 1. Your API will be available at: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space`
80
+ 2. Test the health endpoint: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/health`
81
+ 3. View API documentation: `https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/docs`
82
+
83
+ ## Testing Your Deployment
84
+
85
+ ### Using cURL
86
+
87
+ ```bash
88
+ # Health check
89
+ curl https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/health
90
+
91
+ # Get recommendations (replace user123 with actual user_id)
92
+ curl https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space/recommendations/user123
93
+ ```
94
+
95
+ ### Using Python
96
+
97
+ ```python
98
+ import requests
99
+
100
+ BASE_URL = "https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space"
101
+
102
+ # Health check
103
+ response = requests.get(f"{BASE_URL}/health")
104
+ print(response.json())
105
+
106
+ # Get recommendations
107
+ response = requests.get(f"{BASE_URL}/recommendations/user123")
108
+ print(response.json())
109
+ ```
110
+
111
+ ## Important Notes
112
+
113
+ 1. **Port Configuration**: Hugging Face automatically maps port 8000, so your Dockerfile should expose port 8000 (which it does)
114
+
115
+ 2. **Environment Variables**: The `MONGODB_URI` secret will be automatically available as an environment variable in your container
116
+
117
+ 3. **Cold Starts**: The first request after inactivity may take longer (cold start). Subsequent requests will be faster
118
+
119
+ 4. **Resource Limits**: Free Hugging Face Spaces have resource limits. For production use, consider upgrading
120
+
121
+ 5. **Custom Domain**: You can add a custom domain in Space settings if needed
122
+
123
+ ## Troubleshooting
124
+
125
+ ### Build Fails
126
+
127
+ - Check the **Logs** tab for error messages
128
+ - Ensure `Dockerfile` is in the root directory
129
+ - Verify all required files are uploaded
130
+
131
+ ### Connection Errors
132
+
133
+ - Verify `MONGODB_URI` secret is set correctly
134
+ - Check MongoDB server is accessible from Hugging Face's servers
135
+ - Review connection string encoding (special characters should be URL-encoded)
136
+
137
+ ### API Not Responding
138
+
139
+ - Check the **Logs** tab for runtime errors
140
+ - Verify the application starts successfully
141
+ - Test the `/health` endpoint first
142
+
143
+ ## Updating Your Deployment
144
+
145
+ 1. Make changes to your code locally
146
+ 2. Commit and push to your Space repository
147
+ 3. Hugging Face will automatically rebuild and redeploy
148
+
149
+ ## Support
150
+
151
+ For issues specific to:
152
+ - **Hugging Face Spaces**: Check [Hugging Face Documentation](https://huggingface.co/docs/hub/spaces)
153
+ - **This Application**: Check the main README.md file
154
+
QUICKSTART.md ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quick Start Guide
2
+
3
+ ## Local Development
4
+
5
+ 1. **Install dependencies:**
6
+ ```bash
7
+ pip install -r requirements.txt
8
+ ```
9
+
10
+ 2. **Set environment variable:**
11
+ ```bash
12
+ # Windows PowerShell
13
+ $env:MONGODB_URI="mongodb://expenseuser:Kem_6o%3F%[email protected]:27017/expense?authSource=admin"
14
+
15
+ # Linux/Mac
16
+ export MONGODB_URI="mongodb://expenseuser:Kem_6o%3F%[email protected]:27017/expense?authSource=admin"
17
+ ```
18
+
19
+ 3. **Run the application:**
20
+ ```bash
21
+ uvicorn app.main:app --reload
22
+ ```
23
+
24
+ 4. **Access the API:**
25
+ - API: http://localhost:8000
26
+ - Docs: http://localhost:8000/docs
27
+ - Health: http://localhost:8000/health
28
+
29
+ ## Test the Smart Budget Recommendation
30
+
31
+ 1. **Create some sample expenses:**
32
+ ```bash
33
+ curl -X POST "http://localhost:8000/expenses" \
34
+ -H "Content-Type: application/json" \
35
+ -d '{
36
+ "user_id": "user123",
37
+ "amount": 3800,
38
+ "category": "Groceries",
39
+ "description": "Monthly groceries",
40
+ "date": "2024-01-15T00:00:00",
41
+ "type": "expense"
42
+ }'
43
+ ```
44
+
45
+ 2. **Get recommendations:**
46
+ ```bash
47
+ curl "http://localhost:8000/recommendations/user123?month=2&year=2024"
48
+ ```
49
+
50
+ Expected response:
51
+ ```json
52
+ [
53
+ {
54
+ "category": "Groceries",
55
+ "average_expense": 3800.0,
56
+ "recommended_budget": 4000.0,
57
+ "reason": "Your average monthly grocery expense is Rs.3,800. We suggest setting your budget to Rs.4,000 for next month (includes a 5% buffer for variability).",
58
+ "confidence": 0.85
59
+ }
60
+ ]
61
+ ```
62
+
63
+ ## Docker Deployment
64
+
65
+ 1. **Build the image:**
66
+ ```bash
67
+ docker build -t smart-budget-recommendation .
68
+ ```
69
+
70
+ 2. **Run the container:**
71
+ ```bash
72
+ docker run -p 8000:8000 -e MONGODB_URI="your_mongodb_uri" smart-budget-recommendation
73
+ ```
74
+
75
+ ## Hugging Face Deployment
76
+
77
+ See `HUGGINGFACE_DEPLOYMENT.md` for detailed instructions.
78
+
79
+ Quick steps:
80
+ 1. Create a new Docker Space on Hugging Face
81
+ 2. Add `MONGODB_URI` as a secret
82
+ 3. Upload all files
83
+ 4. Wait for automatic build and deployment
84
+
README.md ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Smart Budget Recommendation API
2
+
3
+ A FastAPI-based service that provides intelligent budget recommendations based on past spending behavior. This service analyzes historical expense data and suggests personalized budgets for each category.
4
+
5
+ ## Features
6
+
7
+ - **Smart Budget Recommendations**: Analyzes past spending patterns and recommends personalized budgets
8
+ - **Category-based Analysis**: Provides recommendations for each expense category
9
+ - **Confidence Scoring**: Each recommendation includes a confidence score based on data quality
10
+ - **MongoDB Integration**: Stores expenses and budgets in MongoDB
11
+ - **RESTful API**: Clean API endpoints for expense tracking and budget management
12
+
13
+ ## Example Recommendation
14
+
15
+ ```json
16
+ {
17
+ "category": "Groceries",
18
+ "average_expense": 3800.0,
19
+ "recommended_budget": 4000.0,
20
+ "reason": "Your average monthly grocery expense is Rs.3,800. We suggest setting your budget to Rs.4,000 for next month (includes a 5% buffer for variability).",
21
+ "confidence": 0.85
22
+ }
23
+ ```
24
+
25
+ ## API Endpoints
26
+
27
+ ### Health Check
28
+ - `GET /health` - Check API and database connection status
29
+
30
+ ### Expenses
31
+ - `POST /expenses` - Create a new expense
32
+ - `GET /expenses?user_id={user_id}` - Get expenses for a user
33
+
34
+ ### Budgets
35
+ - `POST /budgets` - Create a new budget
36
+ - `GET /budgets?user_id={user_id}` - Get budgets for a user
37
+
38
+ ### Recommendations
39
+ - `GET /recommendations/{user_id}?month={month}&year={year}` - Get smart budget recommendations
40
+ - `GET /category-expenses/{user_id}?months={months}` - Get average expenses by category
41
+
42
+ ## Local Development
43
+
44
+ ### Prerequisites
45
+ - Python 3.11+
46
+ - MongoDB connection string
47
+
48
+ ### Setup
49
+
50
+ 1. Install dependencies:
51
+ ```bash
52
+ pip install -r requirements.txt
53
+ ```
54
+
55
+ 2. Set environment variable:
56
+ ```bash
57
+ export MONGODB_URI="mongodb://expenseuser:Kem_6o%3F%[email protected]:27017/expense?authSource=admin"
58
+ ```
59
+
60
+ 3. Run the application:
61
+ ```bash
62
+ uvicorn app.main:app --reload
63
+ ```
64
+
65
+ The API will be available at `http://localhost:8000`
66
+
67
+ ## Docker Deployment
68
+
69
+ ### Build Docker Image
70
+ ```bash
71
+ docker build -t smart-budget-recommendation .
72
+ ```
73
+
74
+ ### Run Docker Container
75
+ ```bash
76
+ docker run -p 8000:8000 -e MONGODB_URI="your_mongodb_uri" smart-budget-recommendation
77
+ ```
78
+
79
+ ## Hugging Face Deployment
80
+
81
+ ### Prerequisites
82
+ 1. Hugging Face account
83
+ 2. Docker installed
84
+ 3. MongoDB connection string stored as a secret in Hugging Face
85
+
86
+ ### Steps
87
+
88
+ 1. **Store MongoDB URI as Secret in Hugging Face**:
89
+ - Go to your Hugging Face Space settings
90
+ - Navigate to "Variables and secrets"
91
+ - Add a new secret named `MONGODB_URI` with your MongoDB connection string
92
+
93
+ 2. **Create Hugging Face Space**:
94
+ - Create a new Space on Hugging Face
95
+ - Choose "Docker" as the SDK
96
+
97
+ 3. **Upload Files**:
98
+ - Upload all files from this repository to your Space
99
+ - Ensure `Dockerfile` is in the root directory
100
+
101
+ 4. **Configure Space**:
102
+ - The Dockerfile will automatically build and run the application
103
+ - The app will use the `MONGODB_URI` secret from Hugging Face environment variables
104
+
105
+ ### Hugging Face Space Configuration
106
+
107
+ The Dockerfile is configured to:
108
+ - Use Python 3.11
109
+ - Install all dependencies
110
+ - Expose port 8000
111
+ - Run the FastAPI application with Uvicorn
112
+
113
+ Hugging Face will automatically:
114
+ - Build the Docker image
115
+ - Set environment variables from secrets
116
+ - Deploy the container
117
+ - Provide a public URL
118
+
119
+ ## API Documentation
120
+
121
+ Once deployed, access interactive API documentation at:
122
+ - Swagger UI: `http://your-url/docs`
123
+ - ReDoc: `http://your-url/redoc`
124
+
125
+ ## Algorithm Details
126
+
127
+ The Smart Budget Recommendation engine:
128
+
129
+ 1. **Data Collection**: Analyzes expenses from the past 6 months
130
+ 2. **Category Analysis**: Groups expenses by category and calculates:
131
+ - Average monthly spending
132
+ - Standard deviation (variability)
133
+ - Number of transactions
134
+ - Months of data available
135
+ 3. **Budget Calculation**:
136
+ - Base: Average monthly expense
137
+ - Buffer: 5-10% based on spending variability
138
+ - Rounding: Rounds to nearest 100 for cleaner numbers
139
+ 4. **Confidence Scoring**:
140
+ - Based on data quality (months analyzed, transaction count, consistency)
141
+ - Returns score from 0-1
142
+
143
+ ## Environment Variables
144
+
145
+ - `MONGODB_URI`: MongoDB connection string (required)
146
+
147
+ ## License
148
+
149
+ Copyright © 2025 WalletSync. All Rights Reserved
150
+
app.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "sdk": "docker",
3
+ "sdk_version": "3.0.0",
4
+ "app_file": "app/main.py"
5
+ }
6
+
app/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Smart Budget Recommendation API
2
+
app/main.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Depends
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pymongo import MongoClient
4
+ from pymongo.errors import ConnectionFailure
5
+ import os
6
+ from typing import List, Optional
7
+ from datetime import datetime, timedelta
8
+ from models import BudgetRecommendation, Expense, Budget, CategoryExpense
9
+ from smart_recommendation import SmartBudgetRecommender
10
+
11
+ app = FastAPI(title="Smart Budget Recommendation API", version="1.0.0")
12
+
13
+ # CORS middleware
14
+ app.add_middleware(
15
+ CORSMiddleware,
16
+ allow_origins=["*"],
17
+ allow_credentials=True,
18
+ allow_methods=["*"],
19
+ allow_headers=["*"],
20
+ )
21
+
22
+ # MongoDB connection - Get from environment variable (set as secret in Hugging Face)
23
+ MONGODB_URI = os.getenv("MONGODB_URI")
24
+ if not MONGODB_URI:
25
+ raise ValueError("MONGODB_URI environment variable is required. Please set it in Hugging Face secrets.")
26
+
27
+ try:
28
+ client = MongoClient(MONGODB_URI)
29
+ db = client.expense
30
+ # Test connection
31
+ client.admin.command('ping')
32
+ print("Successfully connected to MongoDB")
33
+ except ConnectionFailure as e:
34
+ print(f"Failed to connect to MongoDB: {e}")
35
+ raise
36
+
37
+ # Initialize Smart Budget Recommender
38
+ recommender = SmartBudgetRecommender(db)
39
+
40
+ @app.get("/")
41
+ async def root():
42
+ return {"message": "Smart Budget Recommendation API", "status": "running"}
43
+
44
+ @app.get("/health")
45
+ async def health_check():
46
+ try:
47
+ client.admin.command('ping')
48
+ return {"status": "healthy", "database": "connected"}
49
+ except Exception as e:
50
+ return {"status": "unhealthy", "error": str(e)}
51
+
52
+ @app.post("/expenses", response_model=dict)
53
+ async def create_expense(expense: Expense):
54
+ """Create a new expense"""
55
+ expense_dict = expense.model_dump()
56
+ expense_dict["created_at"] = datetime.utcnow()
57
+ result = db.expenses.insert_one(expense_dict)
58
+ return {"id": str(result.inserted_id), "message": "Expense created successfully"}
59
+
60
+ @app.get("/expenses", response_model=List[Expense])
61
+ async def get_expenses(user_id: str, limit: int = 100):
62
+ """Get expenses for a user"""
63
+ expenses = list(db.expenses.find({"user_id": user_id}).sort("date", -1).limit(limit))
64
+ for expense in expenses:
65
+ expense["id"] = str(expense["_id"])
66
+ del expense["_id"]
67
+ return expenses
68
+
69
+ @app.post("/budgets", response_model=dict)
70
+ async def create_budget(budget: Budget):
71
+ """Create a new budget"""
72
+ budget_dict = budget.model_dump()
73
+ budget_dict["created_at"] = datetime.utcnow()
74
+ result = db.budgets.insert_one(budget_dict)
75
+ return {"id": str(result.inserted_id), "message": "Budget created successfully"}
76
+
77
+ @app.get("/budgets", response_model=List[Budget])
78
+ async def get_budgets(user_id: str):
79
+ """Get budgets for a user"""
80
+ budgets = list(db.budgets.find({"user_id": user_id}))
81
+ for budget in budgets:
82
+ budget["id"] = str(budget["_id"])
83
+ del budget["_id"]
84
+ return budgets
85
+
86
+ @app.get("/recommendations/{user_id}", response_model=List[BudgetRecommendation])
87
+ async def get_budget_recommendations(user_id: str, month: Optional[int] = None, year: Optional[int] = None):
88
+ """
89
+ Get smart budget recommendations for a user based on past spending behavior.
90
+
91
+ Example response:
92
+ {
93
+ "category": "Groceries",
94
+ "average_expense": 3800,
95
+ "recommended_budget": 4000,
96
+ "reason": "Your average monthly grocery expense is Rs.3,800. We suggest setting your budget to Rs.4,000 for next month."
97
+ }
98
+ """
99
+ if not month or not year:
100
+ # Default to next month
101
+ next_month = datetime.now().replace(day=1) + timedelta(days=32)
102
+ month = next_month.month
103
+ year = next_month.year
104
+
105
+ recommendations = recommender.get_recommendations(user_id, month, year)
106
+ return recommendations
107
+
108
+ @app.get("/category-expenses/{user_id}", response_model=List[CategoryExpense])
109
+ async def get_category_expenses(user_id: str, months: int = 3):
110
+ """Get average expenses by category for the past N months"""
111
+ category_expenses = recommender.get_category_averages(user_id, months)
112
+ return category_expenses
113
+
114
+ if __name__ == "__main__":
115
+ import uvicorn
116
+ uvicorn.run(app, host="0.0.0.0", port=8000)
117
+
app/models.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import Optional
3
+ from datetime import datetime
4
+ from enum import Enum
5
+
6
+ class ExpenseType(str, Enum):
7
+ INCOME = "income"
8
+ EXPENSE = "expense"
9
+
10
+ class Expense(BaseModel):
11
+ user_id: str
12
+ amount: float = Field(..., gt=0, description="Expense amount")
13
+ category: str = Field(..., description="Expense category (e.g., Groceries, Transport)")
14
+ description: Optional[str] = None
15
+ date: datetime
16
+ type: ExpenseType = ExpenseType.EXPENSE
17
+
18
+ class Budget(BaseModel):
19
+ user_id: str
20
+ category: str
21
+ amount: float = Field(..., gt=0, description="Budget amount")
22
+ period: str = Field(..., description="Budget period: daily, weekly, monthly, yearly")
23
+ start_date: datetime
24
+ end_date: Optional[datetime] = None
25
+
26
+ class BudgetRecommendation(BaseModel):
27
+ category: str
28
+ average_expense: float
29
+ recommended_budget: float
30
+ reason: str
31
+ confidence: float = Field(..., ge=0, le=1, description="Confidence score (0-1)")
32
+
33
+ class CategoryExpense(BaseModel):
34
+ category: str
35
+ average_monthly_expense: float
36
+ total_expenses: int
37
+ months_analyzed: int
38
+
app/smart_recommendation.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime, timedelta
2
+ from typing import List, Dict
3
+ from collections import defaultdict
4
+ from models import BudgetRecommendation, CategoryExpense
5
+ import math
6
+
7
+ class SmartBudgetRecommender:
8
+ """
9
+ Smart Budget Recommendation Engine
10
+
11
+ Analyzes past spending behavior and recommends personalized budgets
12
+ for each category based on historical data.
13
+ """
14
+
15
+ def __init__(self, db):
16
+ self.db = db
17
+
18
+ def get_recommendations(self, user_id: str, month: int, year: int) -> List[BudgetRecommendation]:
19
+ """
20
+ Get budget recommendations for all categories based on past behavior.
21
+
22
+ Args:
23
+ user_id: User identifier
24
+ month: Target month (1-12)
25
+ year: Target year
26
+
27
+ Returns:
28
+ List of budget recommendations for each category
29
+ """
30
+ # Get past expenses (last 6 months for better accuracy)
31
+ end_date = datetime(year, month, 1) - timedelta(days=1)
32
+ start_date = end_date - timedelta(days=180) # ~6 months
33
+
34
+ expenses = list(self.db.expenses.find({
35
+ "user_id": user_id,
36
+ "date": {"$gte": start_date, "$lte": end_date},
37
+ "type": "expense"
38
+ }))
39
+
40
+ if not expenses:
41
+ return []
42
+
43
+ # Group expenses by category and calculate monthly averages
44
+ category_data = self._calculate_category_statistics(expenses, start_date, end_date)
45
+
46
+ recommendations = []
47
+ for category, data in category_data.items():
48
+ avg_expense = data["average_monthly"]
49
+ recommended_budget = self._calculate_recommended_budget(avg_expense, data)
50
+ confidence = self._calculate_confidence(data)
51
+
52
+ reason = self._generate_reason(category, avg_expense, recommended_budget)
53
+
54
+ recommendations.append(BudgetRecommendation(
55
+ category=category,
56
+ average_expense=round(avg_expense, 2),
57
+ recommended_budget=round(recommended_budget, 2),
58
+ reason=reason,
59
+ confidence=confidence
60
+ ))
61
+
62
+ # Sort by average expense (highest first)
63
+ recommendations.sort(key=lambda x: x.average_expense, reverse=True)
64
+
65
+ return recommendations
66
+
67
+ def _calculate_category_statistics(self, expenses: List[Dict], start_date: datetime, end_date: datetime) -> Dict:
68
+ """Calculate statistics for each category"""
69
+ category_data = defaultdict(lambda: {
70
+ "total": 0,
71
+ "count": 0,
72
+ "months": set(),
73
+ "monthly_totals": defaultdict(float)
74
+ })
75
+
76
+ for expense in expenses:
77
+ category = expense.get("category", "Uncategorized")
78
+ amount = expense.get("amount", 0)
79
+ date = expense.get("date")
80
+
81
+ if isinstance(date, str):
82
+ date = datetime.fromisoformat(date.replace('Z', '+00:00'))
83
+
84
+ category_data[category]["total"] += amount
85
+ category_data[category]["count"] += 1
86
+
87
+ # Track monthly totals
88
+ month_key = (date.year, date.month)
89
+ category_data[category]["months"].add(month_key)
90
+ category_data[category]["monthly_totals"][month_key] += amount
91
+
92
+ # Calculate averages
93
+ result = {}
94
+ for category, data in category_data.items():
95
+ num_months = len(data["months"]) or 1
96
+ avg_monthly = data["total"] / num_months
97
+
98
+ # Calculate standard deviation for variability
99
+ monthly_values = list(data["monthly_totals"].values())
100
+ if len(monthly_values) > 1:
101
+ mean = sum(monthly_values) / len(monthly_values)
102
+ variance = sum((x - mean) ** 2 for x in monthly_values) / len(monthly_values)
103
+ std_dev = math.sqrt(variance)
104
+ else:
105
+ std_dev = 0
106
+
107
+ result[category] = {
108
+ "average_monthly": avg_monthly,
109
+ "total": data["total"],
110
+ "count": data["count"],
111
+ "months_analyzed": num_months,
112
+ "std_dev": std_dev,
113
+ "monthly_values": monthly_values
114
+ }
115
+
116
+ return result
117
+
118
+ def _calculate_recommended_budget(self, avg_expense: float, data: Dict) -> float:
119
+ """
120
+ Calculate recommended budget based on average expense.
121
+
122
+ Strategy:
123
+ - Base: Average monthly expense
124
+ - Add 5% buffer for variability
125
+ - Round to nearest 100 for cleaner numbers
126
+ """
127
+ # Add 5% buffer to handle variability
128
+ buffer = avg_expense * 0.05
129
+
130
+ # If there's high variability (std_dev > 20% of mean), add more buffer
131
+ if data["std_dev"] > 0:
132
+ coefficient_of_variation = data["std_dev"] / avg_expense if avg_expense > 0 else 0
133
+ if coefficient_of_variation > 0.2:
134
+ buffer = avg_expense * 0.10 # 10% buffer for high variability
135
+
136
+ recommended = avg_expense + buffer
137
+
138
+ # Round to nearest 100 for cleaner budget numbers
139
+ recommended = round(recommended / 100) * 100
140
+
141
+ # Ensure minimum of 100 if there was any expense
142
+ if recommended < 100 and avg_expense > 0:
143
+ recommended = 100
144
+
145
+ return recommended
146
+
147
+ def _calculate_confidence(self, data: Dict) -> float:
148
+ """
149
+ Calculate confidence score (0-1) based on data quality.
150
+
151
+ Factors:
152
+ - Number of months analyzed (more = higher confidence)
153
+ - Number of transactions (more = higher confidence)
154
+ - Consistency of spending (lower std_dev = higher confidence)
155
+ """
156
+ months_score = min(data["months_analyzed"] / 6, 1.0) # Max at 6 months
157
+ count_score = min(data["count"] / 10, 1.0) # Max at 10 transactions
158
+
159
+ # Consistency score (inverse of coefficient of variation)
160
+ if data["average_monthly"] > 0:
161
+ cv = data["std_dev"] / data["average_monthly"]
162
+ consistency_score = max(0, 1 - min(cv, 1.0)) # Lower CV = higher score
163
+ else:
164
+ consistency_score = 0.5
165
+
166
+ # Weighted average
167
+ confidence = (months_score * 0.4 + count_score * 0.3 + consistency_score * 0.3)
168
+
169
+ return round(confidence, 2)
170
+
171
+ def _generate_reason(self, category: str, avg_expense: float, recommended_budget: float) -> str:
172
+ """Generate human-readable reason for the recommendation"""
173
+ # Format amounts with currency symbol
174
+ avg_formatted = f"Rs.{avg_expense:,.0f}"
175
+ budget_formatted = f"Rs.{recommended_budget:,.0f}"
176
+
177
+ if recommended_budget > avg_expense:
178
+ buffer = recommended_budget - avg_expense
179
+ buffer_pct = (buffer / avg_expense * 100) if avg_expense > 0 else 0
180
+ return (
181
+ f"Your average monthly {category.lower()} expense is {avg_formatted}. "
182
+ f"We suggest setting your budget to {budget_formatted} for next month "
183
+ f"(includes a {buffer_pct:.0f}% buffer for variability)."
184
+ )
185
+ else:
186
+ return (
187
+ f"Your average monthly {category.lower()} expense is {avg_formatted}. "
188
+ f"We recommend a budget of {budget_formatted} for next month."
189
+ )
190
+
191
+ def get_category_averages(self, user_id: str, months: int = 3) -> List[CategoryExpense]:
192
+ """Get average expenses by category for the past N months"""
193
+ end_date = datetime.now()
194
+ start_date = end_date - timedelta(days=months * 30)
195
+
196
+ expenses = list(self.db.expenses.find({
197
+ "user_id": user_id,
198
+ "date": {"$gte": start_date, "$lte": end_date},
199
+ "type": "expense"
200
+ }))
201
+
202
+ if not expenses:
203
+ return []
204
+
205
+ category_data = self._calculate_category_statistics(expenses, start_date, end_date)
206
+
207
+ result = []
208
+ for category, data in category_data.items():
209
+ result.append(CategoryExpense(
210
+ category=category,
211
+ average_monthly_expense=round(data["average_monthly"], 2),
212
+ total_expenses=data["count"],
213
+ months_analyzed=data["months_analyzed"]
214
+ ))
215
+
216
+ result.sort(key=lambda x: x.average_monthly_expense, reverse=True)
217
+ return result
218
+
example_usage.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Example usage of the Smart Budget Recommendation API
3
+
4
+ This script demonstrates how to use the API endpoints.
5
+ """
6
+
7
+ import requests
8
+ from datetime import datetime
9
+
10
+ # Base URL - Update this to your deployed Hugging Face Space URL
11
+ BASE_URL = "http://localhost:8000" # Change to your Hugging Face Space URL
12
+
13
+ # Example user ID
14
+ USER_ID = "user123"
15
+
16
+ def create_sample_expenses():
17
+ """Create sample expenses for testing"""
18
+ expenses = [
19
+ {
20
+ "user_id": USER_ID,
21
+ "amount": 3500,
22
+ "category": "Groceries",
23
+ "description": "Monthly groceries",
24
+ "date": "2024-01-15T00:00:00",
25
+ "type": "expense"
26
+ },
27
+ {
28
+ "user_id": USER_ID,
29
+ "amount": 4000,
30
+ "category": "Groceries",
31
+ "description": "Monthly groceries",
32
+ "date": "2024-02-15T00:00:00",
33
+ "type": "expense"
34
+ },
35
+ {
36
+ "user_id": USER_ID,
37
+ "amount": 3800,
38
+ "category": "Groceries",
39
+ "description": "Monthly groceries",
40
+ "date": "2024-03-15T00:00:00",
41
+ "type": "expense"
42
+ },
43
+ {
44
+ "user_id": USER_ID,
45
+ "amount": 4200,
46
+ "category": "Groceries",
47
+ "description": "Monthly groceries",
48
+ "date": "2024-04-15T00:00:00",
49
+ "type": "expense"
50
+ },
51
+ {
52
+ "user_id": USER_ID,
53
+ "amount": 2000,
54
+ "category": "Transport",
55
+ "description": "Monthly transport",
56
+ "date": "2024-01-20T00:00:00",
57
+ "type": "expense"
58
+ },
59
+ {
60
+ "user_id": USER_ID,
61
+ "amount": 2200,
62
+ "category": "Transport",
63
+ "description": "Monthly transport",
64
+ "date": "2024-02-20T00:00:00",
65
+ "type": "expense"
66
+ },
67
+ ]
68
+
69
+ print("Creating sample expenses...")
70
+ for expense in expenses:
71
+ response = requests.post(f"{BASE_URL}/expenses", json=expense)
72
+ if response.status_code == 200:
73
+ print(f"✓ Created expense: {expense['category']} - Rs.{expense['amount']}")
74
+ else:
75
+ print(f"✗ Failed to create expense: {response.text}")
76
+
77
+ def get_recommendations():
78
+ """Get budget recommendations"""
79
+ print("\n" + "="*50)
80
+ print("Getting Smart Budget Recommendations...")
81
+ print("="*50)
82
+
83
+ # Get recommendations for next month
84
+ next_month = datetime.now().month + 1
85
+ next_year = datetime.now().year
86
+ if next_month > 12:
87
+ next_month = 1
88
+ next_year += 1
89
+
90
+ response = requests.get(
91
+ f"{BASE_URL}/recommendations/{USER_ID}",
92
+ params={"month": next_month, "year": next_year}
93
+ )
94
+
95
+ if response.status_code == 200:
96
+ recommendations = response.json()
97
+ print(f"\nFound {len(recommendations)} recommendations:\n")
98
+
99
+ for rec in recommendations:
100
+ print(f"Category: {rec['category']}")
101
+ print(f" Average Expense: Rs.{rec['average_expense']:,.0f}")
102
+ print(f" Recommended Budget: Rs.{rec['recommended_budget']:,.0f}")
103
+ print(f" Confidence: {rec['confidence']*100:.0f}%")
104
+ print(f" Reason: {rec['reason']}")
105
+ print()
106
+ else:
107
+ print(f"Error: {response.status_code} - {response.text}")
108
+
109
+ def get_category_expenses():
110
+ """Get category expense averages"""
111
+ print("\n" + "="*50)
112
+ print("Getting Category Expense Averages...")
113
+ print("="*50)
114
+
115
+ response = requests.get(
116
+ f"{BASE_URL}/category-expenses/{USER_ID}",
117
+ params={"months": 3}
118
+ )
119
+
120
+ if response.status_code == 200:
121
+ categories = response.json()
122
+ print(f"\nFound {len(categories)} categories:\n")
123
+
124
+ for cat in categories:
125
+ print(f"{cat['category']}:")
126
+ print(f" Average Monthly: Rs.{cat['average_monthly_expense']:,.0f}")
127
+ print(f" Total Transactions: {cat['total_expenses']}")
128
+ print(f" Months Analyzed: {cat['months_analyzed']}")
129
+ print()
130
+ else:
131
+ print(f"Error: {response.status_code} - {response.text}")
132
+
133
+ if __name__ == "__main__":
134
+ print("Smart Budget Recommendation API - Example Usage")
135
+ print("="*50)
136
+
137
+ # Check health
138
+ print("\nChecking API health...")
139
+ response = requests.get(f"{BASE_URL}/health")
140
+ if response.status_code == 200:
141
+ print(f"✓ API is healthy: {response.json()}")
142
+ else:
143
+ print(f"✗ API health check failed: {response.text}")
144
+ exit(1)
145
+
146
+ # Uncomment to create sample data
147
+ # create_sample_expenses()
148
+
149
+ # Get recommendations
150
+ get_recommendations()
151
+
152
+ # Get category averages
153
+ get_category_expenses()
154
+
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ pymongo==4.6.0
4
+ pydantic==2.5.0
5
+ python-multipart==0.0.6
6
+
test_api.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Simple test script to verify the API is working
3
+ Run this after starting the server to test all endpoints
4
+ """
5
+
6
+ import requests
7
+ import json
8
+ from datetime import datetime
9
+
10
+ # Update this to your API URL
11
+ # For local: http://localhost:8000
12
+ # For Hugging Face: https://your-username-your-space.hf.space
13
+ BASE_URL = "http://localhost:8000"
14
+
15
+ def test_health():
16
+ """Test health endpoint"""
17
+ print("=" * 50)
18
+ print("Testing Health Endpoint")
19
+ print("=" * 50)
20
+ try:
21
+ response = requests.get(f"{BASE_URL}/health")
22
+ print(f"Status Code: {response.status_code}")
23
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
24
+ return response.status_code == 200
25
+ except Exception as e:
26
+ print(f"Error: {e}")
27
+ return False
28
+
29
+ def test_root():
30
+ """Test root endpoint"""
31
+ print("\n" + "=" * 50)
32
+ print("Testing Root Endpoint")
33
+ print("=" * 50)
34
+ try:
35
+ response = requests.get(f"{BASE_URL}/")
36
+ print(f"Status Code: {response.status_code}")
37
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
38
+ return response.status_code == 200
39
+ except Exception as e:
40
+ print(f"Error: {e}")
41
+ return False
42
+
43
+ def test_create_expense():
44
+ """Test creating an expense"""
45
+ print("\n" + "=" * 50)
46
+ print("Testing Create Expense Endpoint")
47
+ print("=" * 50)
48
+ try:
49
+ expense_data = {
50
+ "user_id": "test_user_123",
51
+ "amount": 3800,
52
+ "category": "Groceries",
53
+ "description": "Monthly groceries",
54
+ "date": datetime.now().isoformat(),
55
+ "type": "expense"
56
+ }
57
+ response = requests.post(
58
+ f"{BASE_URL}/expenses",
59
+ json=expense_data,
60
+ headers={"Content-Type": "application/json"}
61
+ )
62
+ print(f"Status Code: {response.status_code}")
63
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
64
+ return response.status_code == 200
65
+ except Exception as e:
66
+ print(f"Error: {e}")
67
+ return False
68
+
69
+ def test_get_expenses():
70
+ """Test getting expenses"""
71
+ print("\n" + "=" * 50)
72
+ print("Testing Get Expenses Endpoint")
73
+ print("=" * 50)
74
+ try:
75
+ response = requests.get(
76
+ f"{BASE_URL}/expenses",
77
+ params={"user_id": "test_user_123", "limit": 10}
78
+ )
79
+ print(f"Status Code: {response.status_code}")
80
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
81
+ return response.status_code == 200
82
+ except Exception as e:
83
+ print(f"Error: {e}")
84
+ return False
85
+
86
+ def test_get_recommendations():
87
+ """Test getting budget recommendations"""
88
+ print("\n" + "=" * 50)
89
+ print("Testing Get Recommendations Endpoint")
90
+ print("=" * 50)
91
+ try:
92
+ # Get recommendations for next month
93
+ next_month = datetime.now().month + 1
94
+ next_year = datetime.now().year
95
+ if next_month > 12:
96
+ next_month = 1
97
+ next_year += 1
98
+
99
+ response = requests.get(
100
+ f"{BASE_URL}/recommendations/test_user_123",
101
+ params={"month": next_month, "year": next_year}
102
+ )
103
+ print(f"Status Code: {response.status_code}")
104
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
105
+ return response.status_code == 200
106
+ except Exception as e:
107
+ print(f"Error: {e}")
108
+ return False
109
+
110
+ def test_get_category_expenses():
111
+ """Test getting category expenses"""
112
+ print("\n" + "=" * 50)
113
+ print("Testing Get Category Expenses Endpoint")
114
+ print("=" * 50)
115
+ try:
116
+ response = requests.get(
117
+ f"{BASE_URL}/category-expenses/test_user_123",
118
+ params={"months": 3}
119
+ )
120
+ print(f"Status Code: {response.status_code}")
121
+ print(f"Response: {json.dumps(response.json(), indent=2)}")
122
+ return response.status_code == 200
123
+ except Exception as e:
124
+ print(f"Error: {e}")
125
+ return False
126
+
127
+ if __name__ == "__main__":
128
+ print("\n" + "=" * 50)
129
+ print("Smart Budget Recommendation API - Test Suite")
130
+ print("=" * 50)
131
+ print(f"\nTesting API at: {BASE_URL}")
132
+ print("\nMake sure the server is running!")
133
+ print("Start server with: uvicorn app.main:app --reload\n")
134
+
135
+ results = []
136
+
137
+ # Test all endpoints
138
+ results.append(("Health Check", test_health()))
139
+ results.append(("Root Endpoint", test_root()))
140
+ results.append(("Create Expense", test_create_expense()))
141
+ results.append(("Get Expenses", test_get_expenses()))
142
+ results.append(("Get Recommendations", test_get_recommendations()))
143
+ results.append(("Get Category Expenses", test_get_category_expenses()))
144
+
145
+ # Summary
146
+ print("\n" + "=" * 50)
147
+ print("Test Summary")
148
+ print("=" * 50)
149
+ for test_name, passed in results:
150
+ status = "✓ PASS" if passed else "✗ FAIL"
151
+ print(f"{status} - {test_name}")
152
+
153
+ passed_count = sum(1 for _, passed in results if passed)
154
+ print(f"\nTotal: {passed_count}/{len(results)} tests passed")
155
+
156
+ print("\n" + "=" * 50)
157
+ print("API Documentation available at:")
158
+ print(f" - Swagger UI: {BASE_URL}/docs")
159
+ print(f" - ReDoc: {BASE_URL}/redoc")
160
+ print("=" * 50)
161
+