Aureon / ai_assistant /views.py
CineDev's picture
Refactor mobile money asset positioning and sync backend engines
a7b5683
Raw
History Blame Contribute Delete
8.33 kB
import os
import requests
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions, status
from django.db.models import Sum
from finance.models import Transaction, Budget
class ChatbotView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
user_message = request.data.get('message')
if not user_message:
return Response({"error": "Message is required"}, status=status.HTTP_400_BAD_REQUEST)
# 1. Gather User Context
user = request.user
# Calculate cash available from profile
cash_available = getattr(user, 'profile', None) and user.profile.cash_available or 0
net_worth = getattr(user, 'profile', None) and user.profile.net_worth or 0
# Get budgets
budgets = Budget.objects.filter(user=user)
budget_context = "\n".join([f"- {b.name}: ${b.spent_amount} spent out of ${b.budget_amount} ({b.status})" for b in budgets])
# Get recent transactions
recent_tx = Transaction.objects.filter(user=user).order_by('-date')[:5]
tx_context = "\n".join([f"- {t.date}: ${t.amount} at {t.merchant} ({t.category})" for t in recent_tx])
context_prompt = f"""You are Aureon's premium AI Financial Assistant. You give concise, professional, and helpful financial advice.
User Profile:
- Available Cash: ₹{cash_available}
- Net Worth: ₹{net_worth}
Active Budgets:
{budget_context if budget_context else "No active budgets."}
Recent Transactions:
{tx_context if tx_context else "No recent transactions."}
Based strictly on this data, answer the user's question in rupees (₹). Do not make up data not present here.
User Question: "{user_message}"
"""
# 2. Call Hugging Face API
hf_api_key = os.getenv('HUGGINGFACE_API_KEY')
if not hf_api_key:
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)
# Using Llama 3.1 8B Instruct via modern Hugging Face OpenAI-compatible Router Endpoint
API_URL = "https://router.huggingface.co/v1/chat/completions"
headers = {
"Authorization": f"Bearer {hf_api_key}",
"Content-Type": "application/json"
}
# OpenAI-compatible context-aware payload
payload = {
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [
{"role": "system", "content": context_prompt},
{"role": "user", "content": user_message}
],
"max_tokens": 300,
"temperature": 0.5
}
try:
response = requests.post(API_URL, headers=headers, json=payload)
if response.status_code == 200:
result = response.json()
if 'choices' in result and len(result['choices']) > 0:
bot_reply = result['choices'][0]['message']['content'].strip()
else:
bot_reply = "I'm sorry, I couldn't generate a response at this time."
return Response({"reply": bot_reply})
else:
return Response({"error": f"AI model error: {response.text}"}, status=status.HTTP_502_BAD_GATEWAY)
except Exception as e:
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
import json
class AIInsightsView(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
user = request.user
cash_available = getattr(user, 'profile', None) and user.profile.cash_available or 0
net_worth = getattr(user, 'profile', None) and user.profile.net_worth or 0
# Get budgets
budgets = Budget.objects.filter(user=user)
budget_context = "\n".join([f"- {b.name}: ${b.spent_amount} spent out of ${b.budget_amount} ({b.status})" for b in budgets])
# Get recent transactions
recent_tx = Transaction.objects.filter(user=user).order_by('-date')[:5]
tx_context = "\n".join([f"- {t.date}: ${t.amount} at {t.merchant} ({t.category})" for t in recent_tx])
context_prompt = f"""You are Aureon's premium AI Financial Assistant. Based on the user's financial profile, generate exactly three helpful financial insights.
User Profile:
- Available Cash: ₹{cash_available}
- Net Worth: ₹{net_worth}
Active Budgets:
{budget_context if budget_context else "No active budgets."}
Recent Transactions:
{tx_context if tx_context else "No recent transactions."}
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:
- "id": unique number 1, 2, 3
- "type": one of "success", "warning", "suggestion", "pattern"
- "title": a very short title
- "message": a helpful one-sentence message
- "savings": optional, an integer number of potential savings in rupees (e.g. 42)
- "detail": a short secondary detail string (e.g. "Keep it up!")
- "options": optional array of 2 strings if type is "suggestion"
Example:
[
{{"id": 1, "type": "success", "title": "Great news!", "message": "You spent 15% less this week on food.", "savings": 25, "detail": "Keep it up!"}},
{{"id": 2, "type": "warning", "title": "Watch out!", "message": "Your subscriptions total ₹45 this month.", "detail": "Consider cancelling unused ones."}},
{{"id": 3, "type": "suggestion", "title": "Smart Suggestion", "message": "You have extra cash.", "options": ["Invest it", "Add to goal"]}}
]
"""
hf_api_key = os.getenv('HUGGINGFACE_API_KEY')
if not hf_api_key:
fallback_insights = [
{"id": 1, "type": "success", "title": "Welcome Aboard!", "message": "Your Aureon setup is complete. Let's start tracking your finances.", "detail": "Nice job!"},
{"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."},
{"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"]}
]
return Response(fallback_insights)
# Using Llama 3.1 8B Instruct via modern Hugging Face OpenAI-compatible Router Endpoint
API_URL = "https://router.huggingface.co/v1/chat/completions"
headers = {
"Authorization": f"Bearer {hf_api_key}",
"Content-Type": "application/json"
}
payload = {
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [
{"role": "user", "content": context_prompt}
],
"max_tokens": 500,
"temperature": 0.3
}
try:
response = requests.post(API_URL, headers=headers, json=payload)
if response.status_code == 200:
result = response.json()
bot_reply = result['choices'][0]['message']['content'].strip() if ('choices' in result and len(result['choices']) > 0) else ""
if bot_reply.startswith("```"):
bot_reply = bot_reply.strip("`").strip("json").strip()
parsed_insights = json.loads(bot_reply)
return Response(parsed_insights)
else:
raise Exception(response.text)
except Exception as e:
fallback_insights = [
{"id": 1, "type": "success", "title": "Safe Balance", "message": f"Your current cash balance is ${cash_available}.", "detail": "Good liquidity status."},
{"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."},
{"id": 3, "type": "pattern", "title": "Clean Sheet", "message": "No abnormal spending patterns detected this week.", "detail": "Nice work!"}
]
return Response(fallback_insights)