devnamdev2003 commited on
Commit
99d3b41
Β·
1 Parent(s): 6aa2adf

add milestone api

Browse files
api/admin.py CHANGED
@@ -1,12 +1,14 @@
1
  from django.contrib import admin
2
- from .models import UserData, AIKey, AppVersion
3
- from .models import Contact , ExpenseLog
 
4
 
5
  @admin.register(Contact)
6
  class ContactAdmin(admin.ModelAdmin):
7
- list_display = ('id', 'name', 'email', 'message')
8
- list_filter = ('id', 'name', 'email')
9
- search_fields = ('id', 'name', 'email', 'message')
 
10
 
11
  @admin.register(AIKey)
12
  class AIKeyAdmin(admin.ModelAdmin):
@@ -48,4 +50,26 @@ class ExpenseLogAdmin(admin.ModelAdmin):
48
  list_display = ("text", "predicted_category", "confidence_score", "created_at")
49
  list_filter = ("predicted_category", "created_at")
50
  search_fields = ("text", "predicted_category")
51
- ordering = ("-created_at",)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from django.contrib import admin
2
+ from .models import MilestoneJsonDataStore, UserData, AIKey, AppVersion
3
+ from .models import Contact, ExpenseLog
4
+
5
 
6
  @admin.register(Contact)
7
  class ContactAdmin(admin.ModelAdmin):
8
+ list_display = ("id", "name", "email", "message")
9
+ list_filter = ("id", "name", "email")
10
+ search_fields = ("id", "name", "email", "message")
11
+
12
 
13
  @admin.register(AIKey)
14
  class AIKeyAdmin(admin.ModelAdmin):
 
50
  list_display = ("text", "predicted_category", "confidence_score", "created_at")
51
  list_filter = ("predicted_category", "created_at")
52
  search_fields = ("text", "predicted_category")
53
+ ordering = ("-created_at",)
54
+
55
+
56
+ @admin.register(MilestoneJsonDataStore)
57
+ class MilestoneJsonDataStoreAdmin(admin.ModelAdmin):
58
+
59
+ list_display = ("id", "field_id", "created_at", "updated_at")
60
+
61
+ list_display_links = ("id", "field_id")
62
+
63
+ search_fields = ("field_id",)
64
+
65
+ list_filter = ("created_at", "updated_at")
66
+
67
+ ordering = ("-created_at",)
68
+
69
+ readonly_fields = ("created_at", "updated_at")
70
+
71
+ fieldsets = (
72
+ ("Basic Info", {"fields": ("field_id",)}),
73
+ ("JSON Data", {"fields": ("json_data",)}),
74
+ ("Timestamps", {"fields": ("created_at", "updated_at")}),
75
+ )
api/apps.py CHANGED
@@ -1,49 +1,46 @@
1
  from django.apps import AppConfig
2
- import torch
3
- from transformers import pipeline
4
- import os
5
 
6
 
7
  class ApiConfig(AppConfig):
8
  default_auto_field = "django.db.models.BigAutoField"
9
  name = "api"
10
 
11
- def ready(self):
12
- # Prevent loading twice (Django sometimes runs ready() twice in dev mode)
13
- if os.environ.get("RUN_MAIN", None) != "true" and not os.environ.get(
14
- "KUBERNETES_PORT"
15
- ):
16
- pass # Keep going if running via Gunicorn or in production
17
 
18
- print("Loading Expense Categorizer AI from cache...")
19
 
20
- device = 0 if torch.cuda.is_available() else -1
21
 
22
- # This will automatically use the cached version built by Docker
23
- self.classifier = pipeline(
24
- "zero-shot-classification",
25
- model="valhalla/distilbart-mnli-12-3",
26
- device=device,
27
- )
28
 
29
- self.categories = [
30
- "Food & Drinks",
31
- "Groceries",
32
- "Shopping",
33
- "Bills & Utilities",
34
- "Entertainment",
35
- "Health",
36
- "Education",
37
- "Subscriptions",
38
- "Travel",
39
- "Rent",
40
- "Family & Friends",
41
- "Miscellaneous",
42
- "Gifts",
43
- "Party",
44
- "Personal Care",
45
- "Home & Hygiene",
46
- "Others",
47
- "Recharge",
48
- ]
49
- print("AI Model loaded successfully!")
 
1
  from django.apps import AppConfig
 
 
 
2
 
3
 
4
  class ApiConfig(AppConfig):
5
  default_auto_field = "django.db.models.BigAutoField"
6
  name = "api"
7
 
8
+ # def ready(self):
9
+ # # Prevent loading twice (Django sometimes runs ready() twice in dev mode)
10
+ # if os.environ.get("RUN_MAIN", None) != "true" and not os.environ.get(
11
+ # "KUBERNETES_PORT"
12
+ # ):
13
+ # pass # Keep going if running via Gunicorn or in production
14
 
15
+ # print("Loading Expense Categorizer AI from cache...")
16
 
17
+ # device = 0 if torch.cuda.is_available() else -1
18
 
19
+ # # This will automatically use the cached version built by Docker
20
+ # self.classifier = pipeline(
21
+ # "zero-shot-classification",
22
+ # model="valhalla/distilbart-mnli-12-3",
23
+ # device=device,
24
+ # )
25
 
26
+ # self.categories = [
27
+ # "Food & Drinks",
28
+ # "Groceries",
29
+ # "Shopping",
30
+ # "Bills & Utilities",
31
+ # "Entertainment",
32
+ # "Health",
33
+ # "Education",
34
+ # "Subscriptions",
35
+ # "Travel",
36
+ # "Rent",
37
+ # "Family & Friends",
38
+ # "Miscellaneous",
39
+ # "Gifts",
40
+ # "Party",
41
+ # "Personal Care",
42
+ # "Home & Hygiene",
43
+ # "Others",
44
+ # "Recharge",
45
+ # ]
46
+ # print("AI Model loaded successfully!")
api/migrations/0004_milestonejsondatastore.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.2.4 on 2026-03-30 05:49
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('api', '0003_expenselog_amount'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name='MilestoneJsonDataStore',
15
+ fields=[
16
+ ('id', models.AutoField(primary_key=True, serialize=False)),
17
+ ('field_id', models.CharField(max_length=255, unique=True)),
18
+ ('json_data', models.JSONField()),
19
+ ('created_at', models.DateTimeField(auto_now_add=True)),
20
+ ('updated_at', models.DateTimeField(auto_now=True)),
21
+ ],
22
+ options={
23
+ 'db_table': 'milestone_json_data_store',
24
+ },
25
+ ),
26
+ ]
api/models.py CHANGED
@@ -67,3 +67,18 @@ class ExpenseLog(models.Model):
67
 
68
  def __str__(self):
69
  return f"{self.predicted_category} (${self.amount}): {self.text[:30]}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  def __str__(self):
69
  return f"{self.predicted_category} (${self.amount}): {self.text[:30]}"
70
+
71
+
72
+ class MilestoneJsonDataStore(models.Model):
73
+ id = models.AutoField(primary_key=True)
74
+ field_id = models.CharField(max_length=255, unique=True)
75
+ json_data = models.JSONField()
76
+
77
+ created_at = models.DateTimeField(auto_now_add=True)
78
+ updated_at = models.DateTimeField(auto_now=True)
79
+
80
+ class Meta:
81
+ db_table = "milestone_json_data_store"
82
+
83
+ def __str__(self):
84
+ return f"{self.id} - {self.field_id}"
api/serializers.py CHANGED
@@ -22,3 +22,14 @@ class ExpenseRequestSerializer(serializers.Serializer):
22
  max_length=500,
23
  help_text="Enter the expense description to categorize (e.g., 'Paid 1500 for electricity')",
24
  )
 
 
 
 
 
 
 
 
 
 
 
 
22
  max_length=500,
23
  help_text="Enter the expense description to categorize (e.g., 'Paid 1500 for electricity')",
24
  )
25
+
26
+
27
+ from rest_framework import serializers
28
+ from .models import MilestoneJsonDataStore
29
+
30
+
31
+ class MilestoneJsonDataSerializer(serializers.ModelSerializer):
32
+
33
+ class Meta:
34
+ model = MilestoneJsonDataStore
35
+ fields = ["id", "field_id", "json_data", "created_at", "updated_at"]
api/urls.py CHANGED
@@ -1,5 +1,7 @@
1
  from django.urls import path
2
- from .views import UserDataPostView, GetFieldView, ContactList1, CategorizeExpenseView
 
 
3
 
4
  urlpatterns = [
5
  path("post/", UserDataPostView.as_view(), name="post_user_data"),
@@ -7,5 +9,7 @@ urlpatterns = [
7
  "<str:field>/<str:identifier>/", GetFieldView.as_view(), name="get_field_data"
8
  ),
9
  path("contact/", ContactList1.as_view()),
10
- path("categorize/", CategorizeExpenseView.as_view(), name="categorize_expense"),
 
 
11
  ]
 
1
  from django.urls import path
2
+ from .views import UserDataPostView, GetFieldView, ContactList1
3
+ from django.urls import path
4
+ from .views import save_json_data, get_json_data
5
 
6
  urlpatterns = [
7
  path("post/", UserDataPostView.as_view(), name="post_user_data"),
 
9
  "<str:field>/<str:identifier>/", GetFieldView.as_view(), name="get_field_data"
10
  ),
11
  path("contact/", ContactList1.as_view()),
12
+ # path("categorize/", CategorizeExpenseView.as_view(), name="categorize_expense"),
13
+ path("milestone/save/post/", save_json_data),
14
+ path("milestone/get/<str:field_id>/", get_json_data),
15
  ]
api/views.py CHANGED
@@ -9,6 +9,11 @@ import uuid
9
  from .models import ExpenseLog
10
  from django.apps import apps
11
  import re
 
 
 
 
 
12
 
13
 
14
  class UserDataPostView(APIView):
@@ -100,50 +105,133 @@ class ContactList1(CreateAPIView):
100
  )
101
 
102
 
103
- class CategorizeExpenseView(GenericAPIView):
104
- # 2. Assign the serializer class to automatically populate the Swagger schema
105
- serializer_class = ExpenseRequestSerializer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- def post(self, request):
108
- # 3. Validate input using the serializer
109
- serializer = self.get_serializer(data=request.data)
110
- if not serializer.is_valid():
111
- return Response(serializer.errors, status=400)
 
 
 
 
 
 
 
 
112
 
113
- expense_text = serializer.validated_data["text"]
114
 
115
- # 4. Extract Amount using Regex
116
- # Matches formats like 150, 1,500, 150.50, 1,500.50
117
- amount_match = re.search(r"\d+(?:,\d+)*(?:\.\d+)?", expense_text)
118
- extracted_amount = (
119
- float(amount_match.group().replace(",", "")) if amount_match else None
 
 
120
  )
121
 
122
- # 5. Use the safe Django app registry to fetch the pre-loaded AI model
123
- api_config = apps.get_app_config("api")
 
 
 
 
 
124
 
125
- result = api_config.classifier(
126
- expense_text,
127
- candidate_labels=api_config.categories,
128
- hypothesis_template="This expense is for {}.",
 
 
 
129
  )
130
 
131
- top_category = result["labels"][0]
132
- confidence_score = result["scores"][0]
133
 
134
- # 6. Save to database
135
- ExpenseLog.objects.create(
136
- text=expense_text,
137
- amount=extracted_amount,
138
- predicted_category=top_category,
139
- confidence_score=confidence_score,
 
 
140
  )
141
 
 
 
 
142
  return Response(
143
  {
144
- "expense": expense_text,
145
- "amount": extracted_amount,
146
- "category": top_category,
147
- "confidence": round(confidence_score * 100, 2),
148
- }
 
 
 
 
 
149
  )
 
9
  from .models import ExpenseLog
10
  from django.apps import apps
11
  import re
12
+ from rest_framework.decorators import api_view
13
+ from rest_framework.response import Response
14
+ from rest_framework import status
15
+ from .models import MilestoneJsonDataStore
16
+ from .serializers import MilestoneJsonDataSerializer
17
 
18
 
19
  class UserDataPostView(APIView):
 
105
  )
106
 
107
 
108
+ # class CategorizeExpenseView(GenericAPIView):
109
+ # # 2. Assign the serializer class to automatically populate the Swagger schema
110
+ # serializer_class = ExpenseRequestSerializer
111
+
112
+ # def post(self, request):
113
+ # # 3. Validate input using the serializer
114
+ # serializer = self.get_serializer(data=request.data)
115
+ # if not serializer.is_valid():
116
+ # return Response(serializer.errors, status=400)
117
+
118
+ # expense_text = serializer.validated_data["text"]
119
+
120
+ # # 4. Extract Amount using Regex
121
+ # # Matches formats like 150, 1,500, 150.50, 1,500.50
122
+ # amount_match = re.search(r"\d+(?:,\d+)*(?:\.\d+)?", expense_text)
123
+ # extracted_amount = (
124
+ # float(amount_match.group().replace(",", "")) if amount_match else None
125
+ # )
126
+
127
+ # # 5. Use the safe Django app registry to fetch the pre-loaded AI model
128
+ # api_config = apps.get_app_config("api")
129
+
130
+ # result = api_config.classifier(
131
+ # expense_text,
132
+ # candidate_labels=api_config.categories,
133
+ # hypothesis_template="This expense is for {}.",
134
+ # )
135
+
136
+ # top_category = result["labels"][0]
137
+ # confidence_score = result["scores"][0]
138
+
139
+ # # 6. Save to database
140
+ # ExpenseLog.objects.create(
141
+ # text=expense_text,
142
+ # amount=extracted_amount,
143
+ # predicted_category=top_category,
144
+ # confidence_score=confidence_score,
145
+ # )
146
+
147
+ # return Response(
148
+ # {
149
+ # "expense": expense_text,
150
+ # "amount": extracted_amount,
151
+ # "category": top_category,
152
+ # "confidence": round(confidence_score * 100, 2),
153
+ # }
154
+ # )
155
+
156
+
157
+ @api_view(["POST"])
158
+ def save_json_data(request):
159
+ field_id = request.data.get("field_id")
160
+ json_data = request.data.get("json_data")
161
+
162
+ # βœ… Manual validation (VERY IMPORTANT)
163
+ if not field_id:
164
+ return Response(
165
+ {"message": "field_id is required"},
166
+ status=status.HTTP_400_BAD_REQUEST,
167
+ )
168
 
169
+ if not isinstance(json_data, dict) or not json_data:
170
+ return Response(
171
+ {"message": "json_data must be a non-empty JSON object"},
172
+ status=status.HTTP_400_BAD_REQUEST,
173
+ )
174
+
175
+ # πŸ” Check if exists
176
+ obj = MilestoneJsonDataStore.objects.filter(field_id=field_id).first()
177
+
178
+ if obj:
179
+ # πŸ”„ UPDATE
180
+ obj.json_data = json_data
181
+ obj.save()
182
 
183
+ serializer = MilestoneJsonDataSerializer(obj)
184
 
185
+ return Response(
186
+ {
187
+ "message": "Data updated successfully",
188
+ "flag": 1,
189
+ "data": serializer.data,
190
+ },
191
+ status=status.HTTP_200_OK,
192
  )
193
 
194
+ else:
195
+ # πŸ†• CREATE
196
+ obj = MilestoneJsonDataStore.objects.create(
197
+ field_id=field_id, json_data=json_data
198
+ )
199
+
200
+ serializer = MilestoneJsonDataSerializer(obj)
201
 
202
+ return Response(
203
+ {
204
+ "message": "Data created successfully",
205
+ "flag": 0,
206
+ "data": serializer.data,
207
+ },
208
+ status=status.HTTP_201_CREATED,
209
  )
210
 
 
 
211
 
212
+ @api_view(["GET"])
213
+ def get_json_data(request, field_id):
214
+
215
+ # βœ… Validate input
216
+ if not field_id:
217
+ return Response(
218
+ {"message": "field_id is required", "flag": 0},
219
+ status=status.HTTP_400_BAD_REQUEST,
220
  )
221
 
222
+ try:
223
+ obj = MilestoneJsonDataStore.objects.get(field_id=field_id)
224
+
225
  return Response(
226
  {
227
+ "message": "Data fetched successfully",
228
+ "flag": 1,
229
+ "data": obj.json_data, # πŸ”₯ Only JSON data
230
+ },
231
+ status=status.HTTP_200_OK,
232
+ )
233
+
234
+ except MilestoneJsonDataStore.DoesNotExist:
235
+ return Response(
236
+ {"message": "Data not found", "flag": 0}, status=status.HTTP_404_NOT_FOUND
237
  )
dev.py CHANGED
@@ -3,7 +3,7 @@ import json
3
 
4
  # Replace this URL with your actual Hugging Face Space URL once deployed
5
  # For local testing (e.g., python manage.py runserver), use: "[http://127.0.0.1:8000/api/categorize/](http://127.0.0.1:8000/api/categorize/)"
6
- API_URL = "http://127.0.0.1:8000/api/categorize/"
7
 
8
 
9
  def test_categorize_expense(expense_text):
 
3
 
4
  # Replace this URL with your actual Hugging Face Space URL once deployed
5
  # For local testing (e.g., python manage.py runserver), use: "[http://127.0.0.1:8000/api/categorize/](http://127.0.0.1:8000/api/categorize/)"
6
+ API_URL = "https://coders813-exwiseapi.hf.space/api/categorize/"
7
 
8
 
9
  def test_categorize_expense(expense_text):