Source code for smarter.apps.dashboard.views.passthrough.api.providers

# pylint: disable=W0613
"""
Provider API view for the Dashboard prompt passthrough feature.

This module exposes a JSON API endpoint used by the prompt passthrough React
frontend to retrieve the LLM providers that the currently authenticated user
has read permission for. The provider list is serialised with
:class:`~smarter.apps.provider.serializers.ProviderMiniSerializer` and
returned as a JSON response.

Classes:
    ProviderApiView: Authenticated API view that returns the list of accessible
        LLM providers for the requesting user.

Example:
    Wire up the view in your URL configuration::

        from smarter.apps.dashboard.views.passthrough.api.providers import ProviderApiView

        urlpatterns = [
            path("providers/", ProviderApiView.as_view(), name="api_providers"),
        ]
"""

from django.contrib.auth.decorators import login_required
from django.http import HttpRequest, JsonResponse
from django.utils.decorators import method_decorator

from smarter.apps.account.models import get_resolved_user
from smarter.apps.provider.models import Provider
from smarter.apps.provider.serializers import ProviderSerializer
from smarter.common.utils.decorators import camel_case
from smarter.lib import logging
from smarter.lib.cache import cache_results
from smarter.lib.django.views import (
    SmarterAuthenticatedNeverCachedWebView,
)

logger = logging.getLogger(__name__)


[docs] @method_decorator(login_required, name="dispatch") class ProviderApiView(SmarterAuthenticatedNeverCachedWebView): """ Authenticated JSON API view that returns LLM providers accessible to the requesting user. Extends :class:`~smarter.lib.django.views.SmarterAuthenticatedNeverCachedWebView` to enforce authentication and prevent response caching. On a ``POST`` request the view resolves the authenticated user via :func:`~smarter.apps.account.models.get_resolved_user`, queries :class:`~smarter.apps.provider.models.Provider` for all records the user has read permission for, and returns them serialised as a JSON object. Response shape: .. code-block:: json { "providers": [ { "id": 1, "name": "OpenAI", "base_url": "https://api.openai.com/v1" } ] } Additional provider objects may appear in the ``providers`` array. """ @property def formatted_class_name(self) -> str: """Returns a formatted string of the class name for logging purposes.""" class_name = f"{__name__}.{ProviderApiView.__name__}[{id(self)}]" return self.formatted_text(class_name)
[docs] def post(self, request: HttpRequest, *args, **kwargs) -> JsonResponse: """ Handle POST requests to retrieve LLM providers accessible to the authenticated user. :param request: The incoming HTTP POST request from the client. :type request: django.http.HttpRequest :param args: Additional positional arguments forwarded by the URL dispatcher. :param kwargs: Additional keyword arguments forwarded by the URL dispatcher. :returns: A JSON response containing the list of accessible LLM providers. :rtype: django.http.JsonResponse """ user = get_resolved_user(request.user) @cache_results() @camel_case() def _get_cached_providers_for_user(user_id) -> dict: providers = Provider.objects.with_read_permission_for(user=user).prefetch_related("tags") # type: ignore serialized_providers = ProviderSerializer(providers, many=True).data retval = {"providers": serialized_providers} logger.debug("cached providers for user %s: %s", self.user_profile, logging.formatted_json(retval)) return retval cached_providers = _get_cached_providers_for_user(user.id) # type: ignore return JsonResponse(cached_providers)