CineDev commited on
Commit
bced51f
·
1 Parent(s): bb38b01

feat: update AI assistant views

Browse files
Files changed (1) hide show
  1. ai_assistant/views.py +168 -2
ai_assistant/views.py CHANGED
@@ -1,3 +1,169 @@
1
- from django.shortcuts import render
 
 
 
 
 
 
2
 
3
- # Create your views here.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ from rest_framework.views import APIView
4
+ from rest_framework.response import Response
5
+ from rest_framework import permissions, status
6
+ from django.db.models import Sum
7
+ from finance.models import Transaction, Budget
8
 
9
+ class ChatbotView(APIView):
10
+ permission_classes = [permissions.IsAuthenticated]
11
+
12
+ def post(self, request):
13
+ user_message = request.data.get('message')
14
+ if not user_message:
15
+ return Response({"error": "Message is required"}, status=status.HTTP_400_BAD_REQUEST)
16
+
17
+ # 1. Gather User Context
18
+ user = request.user
19
+
20
+ # Calculate cash available from profile
21
+ cash_available = getattr(user, 'profile', None) and user.profile.cash_available or 0
22
+ net_worth = getattr(user, 'profile', None) and user.profile.net_worth or 0
23
+
24
+ # Get budgets
25
+ budgets = Budget.objects.filter(user=user)
26
+ budget_context = "\n".join([f"- {b.name}: ${b.spent_amount} spent out of ${b.budget_amount} ({b.status})" for b in budgets])
27
+
28
+ # Get recent transactions
29
+ recent_tx = Transaction.objects.filter(user=user).order_by('-date')[:5]
30
+ tx_context = "\n".join([f"- {t.date}: ${t.amount} at {t.merchant} ({t.category})" for t in recent_tx])
31
+
32
+ context_prompt = f"""You are Aureon's premium AI Financial Assistant. You give concise, professional, and helpful financial advice.
33
+ User Profile:
34
+ - Available Cash: ${cash_available}
35
+ - Net Worth: ${net_worth}
36
+ Active Budgets:
37
+ {budget_context if budget_context else "No active budgets."}
38
+ Recent Transactions:
39
+ {tx_context if tx_context else "No recent transactions."}
40
+
41
+ Based strictly on this data, answer the user's question. Do not make up data not present here.
42
+ User Question: "{user_message}"
43
+ """
44
+
45
+ # 2. Call Hugging Face API
46
+ hf_api_key = os.getenv('HUGGINGFACE_API_KEY')
47
+ if not hf_api_key:
48
+ return Response({"error": "Hugging Face API Key is not configured on the server. Please add HUGGINGFACE_API_KEY to your .env file."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
49
+
50
+ # Using Llama 3.1 8B Instruct via modern Hugging Face OpenAI-compatible Router Endpoint
51
+ API_URL = "https://router.huggingface.co/v1/chat/completions"
52
+ headers = {
53
+ "Authorization": f"Bearer {hf_api_key}",
54
+ "Content-Type": "application/json"
55
+ }
56
+
57
+ # OpenAI-compatible context-aware payload
58
+ payload = {
59
+ "model": "meta-llama/Llama-3.1-8B-Instruct",
60
+ "messages": [
61
+ {"role": "system", "content": context_prompt},
62
+ {"role": "user", "content": user_message}
63
+ ],
64
+ "max_tokens": 300,
65
+ "temperature": 0.5
66
+ }
67
+
68
+ try:
69
+ response = requests.post(API_URL, headers=headers, json=payload)
70
+ if response.status_code == 200:
71
+ result = response.json()
72
+ if 'choices' in result and len(result['choices']) > 0:
73
+ bot_reply = result['choices'][0]['message']['content'].strip()
74
+ else:
75
+ bot_reply = "I'm sorry, I couldn't generate a response at this time."
76
+
77
+ return Response({"reply": bot_reply})
78
+ else:
79
+ return Response({"error": f"AI model error: {response.text}"}, status=status.HTTP_502_BAD_GATEWAY)
80
+ except Exception as e:
81
+ return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
82
+
83
+
84
+ import json
85
+
86
+ class AIInsightsView(APIView):
87
+ permission_classes = [permissions.IsAuthenticated]
88
+
89
+ def get(self, request):
90
+ user = request.user
91
+ cash_available = getattr(user, 'profile', None) and user.profile.cash_available or 0
92
+ net_worth = getattr(user, 'profile', None) and user.profile.net_worth or 0
93
+
94
+ # Get budgets
95
+ budgets = Budget.objects.filter(user=user)
96
+ budget_context = "\n".join([f"- {b.name}: ${b.spent_amount} spent out of ${b.budget_amount} ({b.status})" for b in budgets])
97
+
98
+ # Get recent transactions
99
+ recent_tx = Transaction.objects.filter(user=user).order_by('-date')[:5]
100
+ tx_context = "\n".join([f"- {t.date}: ${t.amount} at {t.merchant} ({t.category})" for t in recent_tx])
101
+
102
+ context_prompt = f"""You are Aureon's premium AI Financial Assistant. Based on the user's financial profile, generate exactly three helpful financial insights.
103
+ User Profile:
104
+ - Available Cash: ${cash_available}
105
+ - Net Worth: ${net_worth}
106
+ Active Budgets:
107
+ {budget_context if budget_context else "No active budgets."}
108
+ Recent Transactions:
109
+ {tx_context if tx_context else "No recent transactions."}
110
+
111
+ Provide the output strictly as a JSON array of three objects. Do not include markdown code block formatting (like ```json), other tags, or explanations. Each object must have these exactly:
112
+ - "id": unique number 1, 2, 3
113
+ - "type": one of "success", "warning", "suggestion", "pattern"
114
+ - "title": a very short title
115
+ - "message": a helpful one-sentence message
116
+ - "savings": optional, an integer number of potential savings in dollars (e.g. 42)
117
+ - "detail": a short secondary detail string (e.g. "Keep it up!")
118
+ - "options": optional array of 2 strings if type is "suggestion"
119
+
120
+ Example:
121
+ [
122
+ {{"id": 1, "type": "success", "title": "Great news!", "message": "You spent 15% less this week on food.", "savings": 25, "detail": "Keep it up!"}},
123
+ {{"id": 2, "type": "warning", "title": "Watch out!", "message": "Your subscriptions total $45 this month.", "detail": "Consider cancelling unused ones."}},
124
+ {{"id": 3, "type": "suggestion", "title": "Smart Suggestion", "message": "You have extra cash.", "options": ["Invest it", "Add to goal"]}}
125
+ ]
126
+ """
127
+
128
+ hf_api_key = os.getenv('HUGGINGFACE_API_KEY')
129
+ if not hf_api_key:
130
+ fallback_insights = [
131
+ {"id": 1, "type": "success", "title": "Welcome Aboard!", "message": "Your Aureon setup is complete. Let's start tracking your finances.", "detail": "Nice job!"},
132
+ {"id": 2, "type": "warning", "title": "No Transactions Yet", "message": "Upload a CSV bank statement to get deep Llama-powered insights.", "detail": "Visit Data Import page."},
133
+ {"id": 3, "type": "suggestion", "title": "Set a Saving Goal", "message": "Create your first goal to help Llama calculate targets.", "options": ["Go to Goals", "View suggestions"]}
134
+ ]
135
+ return Response(fallback_insights)
136
+
137
+ # Using Llama 3.1 8B Instruct via modern Hugging Face OpenAI-compatible Router Endpoint
138
+ API_URL = "https://router.huggingface.co/v1/chat/completions"
139
+ headers = {
140
+ "Authorization": f"Bearer {hf_api_key}",
141
+ "Content-Type": "application/json"
142
+ }
143
+ payload = {
144
+ "model": "meta-llama/Llama-3.1-8B-Instruct",
145
+ "messages": [
146
+ {"role": "user", "content": context_prompt}
147
+ ],
148
+ "max_tokens": 500,
149
+ "temperature": 0.3
150
+ }
151
+
152
+ try:
153
+ response = requests.post(API_URL, headers=headers, json=payload)
154
+ if response.status_code == 200:
155
+ result = response.json()
156
+ bot_reply = result['choices'][0]['message']['content'].strip() if ('choices' in result and len(result['choices']) > 0) else ""
157
+ if bot_reply.startswith("```"):
158
+ bot_reply = bot_reply.strip("`").strip("json").strip()
159
+ parsed_insights = json.loads(bot_reply)
160
+ return Response(parsed_insights)
161
+ else:
162
+ raise Exception(response.text)
163
+ except Exception as e:
164
+ fallback_insights = [
165
+ {"id": 1, "type": "success", "title": "Safe Balance", "message": f"Your current cash balance is ${cash_available}.", "detail": "Good liquidity status."},
166
+ {"id": 2, "type": "suggestion", "title": "Create a Budget", "message": "Setting up budgets helps Llama suggest dynamic saving paths.", "detail": "Create one in the Budget tab."},
167
+ {"id": 3, "type": "pattern", "title": "Clean Sheet", "message": "No abnormal spending patterns detected this week.", "detail": "Nice work!"}
168
+ ]
169
+ return Response(fallback_insights)