Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

Commit

Permalink
🛂 Add EntraID Authentication (#4)
Browse files Browse the repository at this point in the history
* 🚀 Initialise project

* 🎨 Add logout button

* 🔧 Authentication via AzureAD

* 🔧  ->
  • Loading branch information
Gary-H9 authored Jul 1, 2024
1 parent 890e297 commit 18971f4
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 14 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CLIENT_ID=<your_client_id>
CLIENT_SECRET=<your_client_secret>
AZURE_TENANT_ID=<your_azure_tenant_id>
REDIRECT_URI=<your_redirect_uri>

# when running locally, you can use
REDIRECT_URI="https://127.0.0.1:8000/azure_auth/callback"
51 changes: 49 additions & 2 deletions ollamate/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,30 @@

from pathlib import Path

import os
import environ

# Initialize environment variables
env = environ.Env()

# Set the project base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Read the .env file
env_file = os.path.join(BASE_DIR, '.env')
if os.path.isfile(env_file):
print(f"Loading environment variables from {env_file}")
environ.Env.read_env(env_file)
else:
print(f"{env_file} not found")
print("CLIENT_ID:", env("CLIENT_ID"))
print("CLIENT_SECRET:", env("CLIENT_SECRET"))
print("TENANT_ID:", env("AZURE_TENANT_ID"))
print("REDIRECT_URI:", env("REDIRECT_URI"))

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/

Expand All @@ -37,7 +57,8 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'streamingapp'
'streamingapp',
'azure_auth'
]

MIDDLEWARE = [
Expand Down Expand Up @@ -122,3 +143,29 @@
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Azure authentication settings

AZURE_AUTH = {
"CLIENT_ID": env("CLIENT_ID"),
"CLIENT_SECRET": env("CLIENT_SECRET"),
"REDIRECT_URI": env("REDIRECT_URI"),
"SCOPES": ["User.Read"],
"AUTHORITY": "https://login.microsoftonline.com/{}".format(env("AZURE_TENANT_ID")), # Or https://login.microsoftonline.com/common if multi-tenant
# # "LOGOUT_URI": "https://<domain>/logout", # Optional
# # "PUBLIC_URLS": ["<public:view_name>",], # Optional, public views accessible by non-authenticated users
# # "PUBLIC_PATHS": ['/go/',], # Optional, public paths accessible by non-authenticated users
# # "ROLES": {
# # "95170e67-2bbf-4e3e-a4d7-e7e5829fe7a7": "GroupName1",
# # "3dc6539e-0589-4663-b782-fef100d839aa": "GroupName2"
# # }, # Optional, will add user to django group if user is in EntraID group
"USERNAME_ATTRIBUTE": "mail", # The AAD attribute or ID token claim you want to use as the value for the user model `USERNAME_FIELD`
# # "EXTRA_FIELDS": [], # Optional, extra AAD user profile attributes you want to make available in the user mapping function
# "USER_MAPPING_FN": "azure_auth.tests.misc.user_mapping_fn", # Optional, path to the function used to map the AAD to Django attributes
}
LOGIN_URL = "/azure_auth/login"
LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = '/'

AUTHENTICATION_BACKENDS = ("azure_auth.backends.AzureBackend",)

5 changes: 4 additions & 1 deletion ollamate/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
"""
from django.contrib import admin
from django.urls import path, include
from streamingapp.views import redirect_to_ollama

urlpatterns = [
path('admin/', admin.site.urls),
path('stream/', include('streamingapp.urls'))
path("azure_auth/", include("azure_auth.urls"),),
path('stream/', include('streamingapp.urls')),
path('', redirect_to_ollama)
]
20 changes: 12 additions & 8 deletions streamingapp/templates/streamingapp/input_form.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
Expand Down Expand Up @@ -43,25 +42,30 @@
<div class="w-full bg-yellow-400 text-center p-2">
<p class="text-black font-bold">A Proof of Concept by the <a href="https://github.com/ministryofjustice/analytical-platform" class="text-blue-700 hover:underline">Analytical Platform</a></p>
</div>
</div>
</div>
<div class="container mx-auto p-4">
<h1 class="text-3xl font-bold mb-4 text-center">Ollamate 🦙🍵</h1>
<h2 class="text-xl font-bold mb-4 text-center">A Simple Conversational AI.</h2>
<p class="mb-4">Enter text below to interact with Ollamate:</p>
<div id="conversation-log" class="bg-white p-4 rounded shadow-lg hidden text-base">
<p class="mb-4 text-center">Logged in as: <strong>{{ user.username }}</strong></p>
<div class="mt-4 text-center">
{% if user.is_authenticated %}
<a href="{% url 'azure_auth:logout' %}" class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Logout</a>
{% else %}
<a href="{% url 'azure_auth:login' %}" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">Login</a>
{% endif %}
</div>
<p class="mb-4">Enter text below to interact with Ollamate:</p>
<div id="conversation-log" class="bg-white p-4 rounded shadow-lg hidden text-base"></div>
<form id="ollamaForm" class="mt-4">
<div class="flex items-center">
<textarea id="userInput" name="userInput" required class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline resize-none"></textarea>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded ml-2">Send</button>
<button type="submit" class="bg-green-500 hover:bg-green-700 text-white py-2 px-4 rounded ml-2">Send</button>
</div>
</form>
</div>

<footer class="bg-gray-800 text-white py-4 mt-8">
<div class="container mx-auto text-center">
<p>📝 <a href="https://github.com/ministryofjustice/analytical-platform" class="text-blue-500 hover:underline">GitHub Repository</a></p>
<p>📝 <a href="https://github.com/ministryofjustice/analytical-platform-ollamate" class="text-blue-500 hover:underline">GitHub Repository</a></p>
</div>
</footer>

Expand Down Expand Up @@ -129,4 +133,4 @@ <h2 class="text-xl font-bold mb-4 text-center">A Simple Conversational AI.</h2>
});
</script>
</body>
</html>
</html>
20 changes: 17 additions & 3 deletions streamingapp/views.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.http import JsonResponse
from azure_auth.decorators import azure_auth_required
import requests
import logging
import json

# Configure logging
logging.basicConfig(level=logging.DEBUG)

@azure_auth_required
def call_ollama(request):
if request.method == 'POST':
user_input = request.POST.get('userInput', '')
conversation_history = json.loads(user_input)
try:
conversation_history = json.loads(user_input)
except json.JSONDecodeError as e:
logging.error("JSONDecodeError: %s", e)
return JsonResponse({"error": "Invalid input format"}, status=400)

url = 'http://localhost:11434/api/chat'
headers = {'Content-Type': 'application/json'}
data = {
"model": "llama3",
"messages": conversation_history,
"stream": False
}

logging.debug("Sending data to Ollama API: %s", json.dumps(data, indent=2))

try:
response = requests.post(url, json=data, headers=headers)
response.raise_for_status()
response_data = response.json()
logging.debug("Response data: %s", json.dumps(response_data, indent=2))
# Extract the actual response message

ollama_response = response_data.get("message", {}).get("content", "")
if not ollama_response:
logging.error("Empty response from Ollama API")
return JsonResponse({"error": "Empty response from Ollama API"}, status=500)

return JsonResponse({"response": ollama_response})
except requests.RequestException as e:
logging.error("RequestException: %s", e)
return JsonResponse({"error": str(e)}, status=500)
else:
return render(request, 'streamingapp/input_form.html')

def redirect_to_ollama(request):
return redirect('/stream/call-ollama')

0 comments on commit 18971f4

Please sign in to comment.