Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
nboyse committed Feb 11, 2025
2 parents 28e9416 + 103a3aa commit f34b41f
Show file tree
Hide file tree
Showing 34 changed files with 3,592 additions and 3,289 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ai.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
echo AZURE_OPENAI_MODEL=azure/gpt-4 >> .env
echo OPENAI_API_VERSION=2024-02-01 >> .env
docker compose up -d --wait elasticsearch
docker compose up -d --wait opensearch
- name: Run DeepEval Unit Tests
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
echo AZURE_OPENAI_API_KEY=${{ secrets.AZURE_OPENAI_API_KEY }} >> .env
echo EMBEDDING_AZURE_OPENAI_ENDPOINT=${{ secrets.AZURE_OPENAI_ENDPOINT }} >> .env
echo EMBEDDING_OPENAI_API_KEY=${{ secrets.AZURE_OPENAI_API_KEY }} >> .env
docker compose up -d --wait elasticsearch minio db
docker compose up -d --wait opensearch minio db
docker compose up -d --wait django-app worker
docker ps
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
mkdir -p data/elastic/
chmod 777 data/elastic/
cp tests/.env.test .env
docker compose up -d --wait elasticsearch
docker compose up -d --wait opensearch
- name: Test redbox with pytest
run: |
Expand Down Expand Up @@ -73,7 +73,7 @@ jobs:
chmod -R 777 data/
cp tests/.env.test .env
sed -i -e "s/^OBJECT_STORE=.*/OBJECT_STORE=minio/" .env
docker compose up -d --wait elasticsearch minio db
docker compose up -d --wait opensearch minio db
docker ps
- name: Test django with pytest
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ test-ai: ## Test code with live LLM

.PHONY: test-redbox
test-redbox: ## Test redbox
cd redbox-core && poetry install && poetry run pytest -m "not ai" --cov=redbox -v --cov-report=term-missing --cov-fail-under=60
cd redbox-core && PYTHONPATH=$(PWD)/django_app:$(PWD)/redbox-core DJANGO_SETTINGS_MODULE=django_app.settings poetry install && \
PYTHONPATH=$(PWD)/django_app:$(PWD)/redbox-core poetry run pytest -m "not ai" --cov=redbox -v --cov-report=term-missing --cov-fail-under=60

.PHONY: test-django
test-django: ## Test django-app
Expand Down Expand Up @@ -89,9 +90,9 @@ reset-db: ## Reset Django database

.PHONY: reset-elastic
reset-elastic: ## Reset Django database
docker compose down elasticsearch
docker compose down opensearch
rm -rf data/elastic/*
docker compose up -d elasticsearch --wait
docker compose up -d opensearch --wait

.PHONY: docs-serve
docs-serve: ## Build and serve documentation
Expand Down
2 changes: 1 addition & 1 deletion ai-tests/tests/test_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def test_usecases(test_case: AITestCase, loaded_docs: set[str], output_dir: Path
with open(save_path, "w") as file:
sys.stdout = file
# Create and add a file handler for logging
file_handler = logging.StreamHandler(file)
logging.StreamHandler(file)
# root_logger.addHandler(file_handler)

# Remove other handlers temporarily if you want logging to go only to file
Expand Down
1 change: 0 additions & 1 deletion django_app/redbox_app/jinja2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import humanize
import jinja2
import pytz
import waffle
from django.conf import settings
from django.templatetags.static import static
from django.urls import reverse
Expand Down
11 changes: 8 additions & 3 deletions django_app/redbox_app/redbox_core/consumers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import json
import logging
from asyncio import CancelledError
from asgiref.sync import sync_to_async
from collections import defaultdict
from collections.abc import Mapping, Sequence
from typing import Any, ClassVar
from uuid import UUID

from asgiref.sync import sync_to_async
from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from django.conf import settings
Expand Down Expand Up @@ -66,7 +66,8 @@ def escape_curly_brackets(text: str):

@sync_to_async
def get_latest_complete_file(ref: str) -> File:
return File.objects.filter(original_file=ref, status=File.Status.complete).order_by('-created_at').first()
return File.objects.filter(original_file=ref, status=File.Status.complete).order_by("-created_at").first()


class ChatConsumer(AsyncWebsocketConsumer):
full_reply: ClassVar = []
Expand Down Expand Up @@ -352,7 +353,11 @@ async def handle_citations(self, citations: list[AICitation]):
# Use the async database query function
file = await get_latest_complete_file(s.source)
if file:
payload = {"url": str(file.url), "file_name": file.file_name, "text_in_answer": c.text_in_answer}
payload = {
"url": str(file.url),
"file_name": file.file_name,
"text_in_answer": c.text_in_answer,
}
else:
# If no file with Status.complete is found, handle it as None
payload = {"url": s.source, "file_name": s.source, "text_in_answer": c.text_in_answer}
Expand Down
11 changes: 10 additions & 1 deletion django_app/redbox_app/redbox_core/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,16 @@ class Meta:
class DemographicsForm(forms.ModelForm):
class Meta:
model = User
fields = ("name", "ai_experience", "business_unit", "role", "grade", "profession", "info_about_user", "redbox_response_preferences")
fields = (
"name",
"ai_experience",
"business_unit",
"role",
"grade",
"profession",
"info_about_user",
"redbox_response_preferences",
)
labels: ClassVar[Mapping[str, str]] = {
"name": "Full Name",
"ai_experience": "How would you describe your level of experience with Generative AI tools?",
Expand Down
15 changes: 9 additions & 6 deletions django_app/redbox_app/redbox_core/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

from asgiref.sync import iscoroutinefunction
from django.conf import settings
from django.contrib.auth import get_user_model
from django.http import HttpRequest, HttpResponse
from django.utils.decorators import sync_and_async_middleware
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from django.contrib.auth import get_user_model

User = get_user_model()


@sync_and_async_middleware
def nocache_middleware(get_response):
if iscoroutinefunction(get_response):
Expand Down Expand Up @@ -81,18 +82,20 @@ def middleware(request: HttpRequest) -> HttpResponse:

return middleware


class APIKeyAuthentication(BaseAuthentication):
def authenticate(self, request):
api_key = request.headers.get('X-API-KEY')
api_key = request.headers.get("X-API-KEY")

if not api_key:
raise AuthenticationFailed('No API key provided')
msg = "No API key provided"
raise AuthenticationFailed(msg)

if api_key == settings.REDBOX_API_KEY:
user, _ = User.objects.get_or_create(
username='api_key_user',
defaults={'is_staff': True, 'is_superuser': False}
username="api_key_user", defaults={"is_staff": True, "is_superuser": False}
)
return (user, None)

raise AuthenticationFailed('Invalid API key')
msg = "Invalid API key"
raise AuthenticationFailed(msg)
43 changes: 29 additions & 14 deletions django_app/redbox_app/redbox_core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
import jwt
from django.conf import settings
from django.contrib.auth.base_user import BaseUserManager as BaseSSOUserManager

# from django_use_email_as_username.models import BaseUser, BaseUserManager
from django.contrib.auth.models import AbstractBaseUser, Group, PermissionsMixin
from django.contrib.postgres.fields import ArrayField
from django.core import validators
from django.db import models
from django.db.models import Max, Min, Prefetch, UniqueConstraint
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

# from django_use_email_as_username.models import BaseUser, BaseUserManager
from django.contrib.auth.models import AbstractBaseUser, Group, PermissionsMixin
from yarl import URL

from redbox.models.settings import get_settings
Expand Down Expand Up @@ -191,12 +191,13 @@ class SSOUserManager(BaseSSOUserManager):
def _create_user(self, username, password, **extra_fields):
"""Create and save a User with the given email and password."""
if not username:
raise ValueError("The given email must be set")
msg = "The given email must be set"
raise ValueError(msg)
# email = self.normalize_email(email)
User = self.model(email=username, **extra_fields)
User.set_password(password)
User.save(using=self._db)
return User
user = self.model(email=username, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user

def create_user(self, username, password=None, **extra_fields):
"""Create and save a regular User with the given email and password."""
Expand All @@ -210,9 +211,11 @@ def create_superuser(self, username, password=None, **extra_fields):
extra_fields.setdefault("is_superuser", True)

if extra_fields.get("is_staff") is not True:
raise ValueError("Superuser must have is_staff=True.")
msg = "Superuser must have is_staff=True."
raise ValueError(msg)
if extra_fields.get("is_superuser") is not True:
raise ValueError("Superuser must have is_superuser=True.")
msg = "Superuser must have is_superuser=True."
raise ValueError(msg)

return self._create_user(username, password, **extra_fields)

Expand Down Expand Up @@ -257,12 +260,24 @@ class Profession(models.TextChoices):
OT = "OT", _("Other")

class BusinessUnit(models.TextChoices):
COMPETITION_MARKETS_AND_REGULATORY_REFORM = "Competition, Markets and Regulatory Reform (CMRR)", _("Competition, Markets and Regulatory Reform (CMRR)")
COMPETITION_MARKETS_AND_REGULATORY_REFORM = (
"Competition, Markets and Regulatory Reform (CMRR)",
_("Competition, Markets and Regulatory Reform (CMRR)"),
)
CORPORATE_SERVICES_GROUP = "Corporate Services Group (CSG)", _("Corporate Services Group (CSG)")
TRADE_POLICY_IMPLEMENTATION_AND_NEGOTIATIONS = "Trade Policy Implementation and Negotiations (TPIN)", _("Trade Policy Implementation and Negotiations (TPIN)")
ECONOMIC_SECURITY_AND_TRADE_RELATIONS = "Economic Security and Trade Relations (ESTR)", _("Economic Security and Trade Relations (ESTR)")
TRADE_POLICY_IMPLEMENTATION_AND_NEGOTIATIONS = (
"Trade Policy Implementation and Negotiations (TPIN)",
_("Trade Policy Implementation and Negotiations (TPIN)"),
)
ECONOMIC_SECURITY_AND_TRADE_RELATIONS = (
"Economic Security and Trade Relations (ESTR)",
_("Economic Security and Trade Relations (ESTR)"),
)
STRATEGY_AND_INVESTMENT = "Strategy and Investment", _("Strategy and Investment")
DOMESTIC_AND_INTERNATIONAL_MARKETS_AND_EXPORTS_GROUP = "Domestic and International Markets and Exports Group (DIME) UK Teams", _("Domestic and International Markets and Exports Group (DIME) UK Teams")
DOMESTIC_AND_INTERNATIONAL_MARKETS_AND_EXPORTS_GROUP = (
"Domestic and International Markets and Exports Group (DIME) UK Teams",
_("Domestic and International Markets and Exports Group (DIME) UK Teams"),
)
BUSINESS_GROUP = "Business Group", _("Business Group")
OVERSEAS_REGIONS = "Overseas Regions", _("Overseas Regions")
INDUSTRIAL_STRATEGY_UNIT = "Industrial Strategy Unit", _("Industrial Strategy Unit")
Expand Down
8 changes: 2 additions & 6 deletions django_app/redbox_app/redbox_core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ class Meta:
class ChatMessageSerializer(serializers.ModelSerializer):
selected_files = FileSerializer(many=True, read_only=True)
source_files = FileSerializer(many=True, read_only=True)
token_use = ChatMessageTokenUseSerializer(
source="chatmessagetokenuse_set", many=True, read_only=True
)
token_use = ChatMessageTokenUseSerializer(source="chatmessagetokenuse_set", many=True, read_only=True)

class Meta:
model = ChatMessage
Expand All @@ -44,9 +42,7 @@ class Meta:


class ChatSerializer(serializers.ModelSerializer):
messages = ChatMessageSerializer(
source="chatmessage_set", many=True, read_only=True
)
messages = ChatMessageSerializer(source="chatmessage_set", many=True, read_only=True)

class Meta:
model = Chat
Expand Down
5 changes: 3 additions & 2 deletions django_app/redbox_app/redbox_core/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from redbox_app.redbox_core.dash_apps import report_app
from redbox_app.redbox_core.views.api_views import user_view_pre_alpha
from redbox_app.redbox_core.views.api_views import message_view_pre_alpha, user_view_pre_alpha
from redbox_app.redbox_core.views.auth_views import sign_in_link_sent_view, sign_in_view, signed_out_view
from redbox_app.redbox_core.views.chat_views import ChatsTitleView, ChatsView, DeleteChat, UpdateChatFeedback
from redbox_app.redbox_core.views.citation_views import CitationsView
Expand All @@ -15,7 +15,7 @@
remove_doc_view,
)
from redbox_app.redbox_core.views.info_views import accessibility_statement_view, privacy_notice_view, support_view
from redbox_app.redbox_core.views.misc_views import SecurityTxtRedirectView, health, homepage_view, faq_view
from redbox_app.redbox_core.views.misc_views import SecurityTxtRedirectView, faq_view, health, homepage_view
from redbox_app.redbox_core.views.ratings_views import RatingsView
from redbox_app.redbox_core.views.signup_views import Signup1, Signup2, Signup3, Signup4, Signup5, Signup6, Signup7

Expand Down Expand Up @@ -51,5 +51,6 @@
"UpdateChatFeedback",
"DeleteChat",
"user_view_pre_alpha",
"message_view_pre_alpha",
"faq_view",
]
23 changes: 18 additions & 5 deletions django_app/redbox_app/redbox_core/views/api_views.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
from django.contrib.auth import get_user_model
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.permissions import IsAdminUser, IsAuthenticated

from redbox_app.redbox_core.serializers import UserSerializer
from redbox_app.redbox_core.models import ChatMessage
from redbox_app.redbox_core.serializers import ChatMessageSerializer, UserSerializer

User = get_user_model()


class StandardResultsSetPagination(PageNumberPagination):
page_size = 50
page_size_query_param = 'page_size'
page_size_query_param = "page_size"
max_page_size = 100


@api_view(["GET"])
@permission_classes([IsAuthenticated, IsAdminUser])
def user_view_pre_alpha(request):
Expand All @@ -21,4 +23,15 @@ def user_view_pre_alpha(request):
queryset = User.objects.all()
result_page = paginator.paginate_queryset(queryset, request)
serializer = UserSerializer(result_page, many=True, read_only=True)
return paginator.get_paginated_response(serializer.data)
return paginator.get_paginated_response(serializer.data)


@api_view(["GET"])
@permission_classes([IsAuthenticated, IsAdminUser])
def message_view_pre_alpha(request):
"""Return paginated message data"""
paginator = StandardResultsSetPagination()
queryset = ChatMessage.objects.all()
result_page = paginator.paginate_queryset(queryset, request)
serializer = ChatMessageSerializer(result_page, many=True, read_only=True)
return paginator.get_paginated_response(serializer.data)
11 changes: 7 additions & 4 deletions django_app/redbox_app/redbox_core/views/document_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.core.exceptions import FieldError, ValidationError, SuspiciousFileOperation
from django.core.exceptions import FieldError, SuspiciousFileOperation, ValidationError
from django.core.files.uploadedfile import UploadedFile
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
Expand Down Expand Up @@ -78,7 +78,7 @@ def post(self, request: HttpRequest) -> HttpResponse:
errors: MutableSequence[str] = []

uploaded_files: MutableSequence[UploadedFile] = request.FILES.getlist("uploadDocs")

if not uploaded_files:
errors.append("No document selected")

Expand Down Expand Up @@ -136,8 +136,11 @@ def ingest_file(uploaded_file: UploadedFile, user: User) -> Sequence[str]:
except (ValueError, FieldError, ValidationError) as e:
logger.exception("Error creating File model object for %s.", uploaded_file, exc_info=e)
return e.args
except SuspiciousFileOperation as e:
return [f"Your file name is {len(uploaded_file.name)} characters long. The file name will need to be shortened by {len(uploaded_file.name) - 75} characters"]
except SuspiciousFileOperation:
return [
f"Your file name is {len(uploaded_file.name)} characters long. "
f"The file name will need to be shortened by {len(uploaded_file.name) - 75} characters"
]
else:
async_task(ingest, file.id, task_name=file.unique_name, group="ingest")

Expand Down
1 change: 0 additions & 1 deletion django_app/redbox_app/redbox_core/views/info_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
These shouldn't contain sensitive data and don't require login.
"""

import waffle
from django.conf import settings
from django.shortcuts import render
from django.views.decorators.http import require_http_methods
Expand Down
Loading

0 comments on commit f34b41f

Please sign in to comment.