Files
voyage/backend/server/main/urls.py
alex 757140ec70 feat(chat): add LLM-powered travel agent with multi-provider support
Implement a full chat-based travel agent using LiteLLM for multi-provider
LLM support (OpenAI, Anthropic, Gemini, Ollama, Groq, Mistral, etc.).

Backend:
- New 'chat' Django app with ChatConversation and ChatMessage models
- Streaming SSE endpoint via StreamingHttpResponse
- 5 agent tools: search_places, list_trips, get_trip_details,
  add_to_itinerary, get_weather
- LiteLLM client wrapper with per-user API key retrieval
- System prompt with user preference context injection

Frontend:
- New /chat route with full-page chat UI (DaisyUI + Tailwind)
- Collapsible conversation sidebar with CRUD
- SSE streaming response display with tool call visualization
- Provider selector dropdown
- SSE proxy fix to stream text/event-stream without buffering
- Navbar link and i18n keys
2026-03-08 18:44:44 +00:00

108 lines
3.6 KiB
Python

from django.urls import include, re_path, path
from django.contrib import admin
from django.views.generic import RedirectView, TemplateView
from users.views import (
IsRegistrationDisabled,
PublicUserListView,
PublicUserDetailView,
UserMetadataView,
UpdateUserMetadataView,
EnabledSocialProvidersView,
DisablePasswordAuthenticationView,
)
from .views import (
get_csrf_token,
get_mcp_api_token,
get_public_url,
serve_protected_media,
)
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from mcp_server.views import MCPServerStreamableHttpView
from django.conf import settings
from django.utils.module_loading import import_string
schema_view = get_schema_view(
openapi.Info(
title="API Docs",
default_version="v1",
)
)
urlpatterns = [
path("api/", include("adventures.urls")),
path("api/", include("worldtravel.urls")),
path("api/chat/", include("chat.urls")),
path(
getattr(settings, "DJANGO_MCP_ENDPOINT", "api/mcp"),
MCPServerStreamableHttpView.as_view(
permission_classes=[
import_string(cls)
for cls in getattr(
settings,
"DJANGO_MCP_ENDPOINT_PERMISSION_CLASSES",
["rest_framework.permissions.IsAuthenticated"],
)
],
authentication_classes=[
import_string(cls)
for cls in getattr(
settings,
"DJANGO_MCP_AUTHENTICATION_CLASSES",
["rest_framework.authentication.TokenAuthentication"],
)
],
),
name="mcp_server_streamable_http_endpoint",
),
path("auth/mcp-token/", get_mcp_api_token, name="get_mcp_api_token"),
path("auth/", include("allauth.headless.urls")),
# Serve protected media files
re_path(
r"^media/(?P<path>.*)$", serve_protected_media, name="serve-protected-media"
),
path(
"auth/is-registration-disabled/",
IsRegistrationDisabled.as_view(),
name="is_registration_disabled",
),
path("auth/users/", PublicUserListView.as_view(), name="public-user-list"),
path(
"auth/user/<str:username>/",
PublicUserDetailView.as_view(),
name="public-user-detail",
),
path(
"auth/update-user/",
UpdateUserMetadataView.as_view(),
name="update-user-metadata",
),
path("auth/user-metadata/", UserMetadataView.as_view(), name="user-metadata"),
path(
"auth/social-providers/",
EnabledSocialProvidersView.as_view(),
name="enabled-social-providers",
),
path(
"auth/disable-password/",
DisablePasswordAuthenticationView.as_view(),
name="disable-password-authentication",
),
path("csrf/", get_csrf_token, name="get_csrf_token"),
path("public-url/", get_public_url, name="get_public_url"),
path("invitations/", include("invitations.urls", namespace="invitations")),
path("", TemplateView.as_view(template_name="home.html")),
re_path(r"^admin/", admin.site.urls),
re_path(
r"^accounts/profile/$",
RedirectView.as_view(url="/", permanent=True),
name="profile-redirect",
),
re_path(
r"^docs/$", schema_view.with_ui("swagger", cache_timeout=0), name="api_docs"
),
# path('auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent'),
path("accounts/", include("allauth.urls")),
path("api/integrations/", include("integrations.urls")),
# Include the API endpoints:
]