Phase 1 - Configuration Infrastructure (WS1): - Add instance-level AI env vars (VOYAGE_AI_PROVIDER, VOYAGE_AI_MODEL, VOYAGE_AI_API_KEY) - Implement fallback chain: user key → instance key → error - Add UserAISettings model for per-user provider/model preferences - Enhance provider catalog with instance_configured and user_configured flags - Optimize provider catalog to avoid N+1 queries Phase 1 - User Preference Learning (WS2): - Add Travel Preferences tab to Settings page - Improve preference formatting in system prompt with emoji headers - Add multi-user preference aggregation for shared collections Phase 2 - Day-Level Suggestions Modal (WS3): - Create ItinerarySuggestionModal with 3-step flow (category → filters → results) - Add AI suggestions button to itinerary Add dropdown - Support restaurant, activity, event, and lodging categories - Backend endpoint POST /api/chat/suggestions/day/ with context-aware prompts Phase 3 - Collection-Level Chat Improvements (WS4): - Inject collection context (destination, dates) into chat system prompt - Add quick action buttons for common queries - Add 'Add to itinerary' button on search_places results - Update chat UI with travel-themed branding and improved tool result cards Phase 3 - Web Search Capability (WS5): - Add web_search agent tool using DuckDuckGo - Support location_context parameter for biased results - Handle rate limiting gracefully Phase 4 - Extensibility Architecture (WS6): - Implement decorator-based @agent_tool registry - Convert existing tools to use decorators - Add GET /api/chat/capabilities/ endpoint for tool discovery - Refactor execute_tool() to use registry pattern
40 lines
1.5 KiB
Python
40 lines
1.5 KiB
Python
from rest_framework import status, viewsets
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
|
|
from integrations.models import UserAISettings
|
|
from integrations.serializers import UserAISettingsSerializer
|
|
|
|
|
|
class UserAISettingsViewSet(viewsets.ModelViewSet):
|
|
serializer_class = UserAISettingsSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return UserAISettings.objects.filter(user=self.request.user)
|
|
|
|
def list(self, request, *args, **kwargs):
|
|
instance = self.get_queryset().first()
|
|
if not instance:
|
|
return Response([], status=status.HTTP_200_OK)
|
|
serializer = self.get_serializer(instance)
|
|
return Response([serializer.data], status=status.HTTP_200_OK)
|
|
|
|
def perform_create(self, serializer):
|
|
existing = UserAISettings.objects.filter(user=self.request.user).first()
|
|
if existing:
|
|
for field, value in serializer.validated_data.items():
|
|
setattr(existing, field, value)
|
|
existing.save()
|
|
self._upserted_instance = existing
|
|
return
|
|
|
|
self._upserted_instance = serializer.save(user=self.request.user)
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
serializer = self.get_serializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
self.perform_create(serializer)
|
|
output = self.get_serializer(self._upserted_instance)
|
|
return Response(output.data, status=status.HTTP_200_OK)
|