Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom rag output #63

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
create grammars in management command
hummerichsander authored Dec 3, 2024
commit b8a3c9f0c5b0364ec92e98fc7f315492d637c2a0
1 change: 1 addition & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ services:
./manage.py create_example_users &&
./manage.py create_example_groups &&
./manage.py populate_example_reports --lng ${EXAMPLE_REPORTS_LANGUAGE:-en} &&
./manage.py create_default_grammars &&
wait-for-it -s llamacpp.local:8080 -t 60 &&
./manage.py runserver 0.0.0.0:8000
"
6 changes: 1 addition & 5 deletions radis/chats/apps.py
Original file line number Diff line number Diff line change
@@ -13,8 +13,7 @@ def ready(self):


def register_app():
from adit_radis_shared.common.site import (MainMenuItem,
register_main_menu_item)
from adit_radis_shared.common.site import MainMenuItem, register_main_menu_item

from radis.reports.site import register_report_panel_button

@@ -29,10 +28,7 @@ def register_app():


def init_db(**kwargs):
from .grammars import create_default_grammars
from .models import ChatsSettings

if not ChatsSettings.objects.exists():
ChatsSettings.objects.create()

create_default_grammars()
20 changes: 20 additions & 0 deletions radis/chats/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import factory

from .models import Grammar


class BaseDjangoModelFactory[T](factory.django.DjangoModelFactory):
@classmethod
def create(cls, *args, **kwargs) -> T:
return super().create(*args, **kwargs)


class GrammarFactory(BaseDjangoModelFactory[Grammar]):
class Meta:
model = Grammar

name = factory.Faker("word")
human_readable_name = factory.Faker("word")
grammar = factory.Faker("sentence")
llm_instruction = factory.Faker("sentence")
is_default = False
107 changes: 0 additions & 107 deletions radis/chats/grammars.py

This file was deleted.

18 changes: 18 additions & 0 deletions radis/chats/migrations/0004_alter_grammar_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.3 on 2024-12-03 12:18

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('chats', '0003_grammar'),
]

operations = [
migrations.AlterField(
model_name='grammar',
name='name',
field=models.CharField(max_length=100, unique=True),
),
]
8 changes: 2 additions & 6 deletions radis/chats/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from operator import is_
from typing import Callable

from adit_radis_shared.common.models import AppSettings
@@ -15,18 +14,15 @@ class Meta:


class Grammar(models.Model):
name = models.CharField(max_length=100)
name = models.CharField(max_length=100, unique=True)
human_readable_name = models.CharField(max_length=100)
grammar = models.TextField()
llm_instruction = models.TextField()

is_default = models.BooleanField(default=False)

def __str__(self):
if self.is_default:
return f"{self.human_readable_name} (default)"
else:
return f"{self.human_readable_name}"
return f"{self.human_readable_name}"


class Chat(models.Model):
9 changes: 9 additions & 0 deletions radis/chats/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import pytest
from faker import Faker

from radis.chats.factories import GrammarFactory
from radis.chats.models import Grammar


@pytest.fixture
def report_body() -> str:
@@ -12,3 +15,9 @@ def report_body() -> str:
def question_body() -> str:
question_body = Faker().sentences(nb=1)
return " ".join(question_body)


@pytest.fixture
def grammar() -> Grammar:
grammar = GrammarFactory.create()
return grammar
25 changes: 16 additions & 9 deletions radis/chats/tests/utils/test_chat_client.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
from unittest.mock import patch

import pytest
from django.db import close_old_connections

from radis.chats.grammars import FreeTextGrammar, YesNoGrammar
from radis.chats.utils.chat_client import AsyncChatClient


@pytest.mark.asyncio
async def test_ask_question(report_body, question_body, openai_chat_completions_mock):
@pytest.mark.django_db(transaction=True)
async def test_ask_question(report_body, question_body, openai_chat_completions_mock, grammar):
openai_mock = openai_chat_completions_mock("Fake Answer")

with patch("openai.AsyncOpenAI", return_value=openai_mock):
answer = await AsyncChatClient().ask_report_question(
context=report_body,
question=question_body,
grammar=FreeTextGrammar,
grammar=grammar,
)

assert answer == "Fake Answer"
assert openai_mock.chat.completions.create.call_count == 1

close_old_connections()


@pytest.mark.asyncio
async def test_ask_yes_no_question(report_body, question_body, openai_chat_completions_mock):
@pytest.mark.django_db(transaction=True)
async def test_ask_yes_no_question(
report_body, question_body, openai_chat_completions_mock, grammar
):
openai_yes_mock = openai_chat_completions_mock("Yes")
openai_no_mock = openai_chat_completions_mock("No")

with patch("openai.AsyncOpenAI", return_value=openai_yes_mock):
answer = await AsyncChatClient().ask_report_question(
context=report_body, question=question_body, grammar=YesNoGrammar
context=report_body, question=question_body, grammar=grammar
)

assert answer == "yes"
assert answer == "Yes"
assert openai_yes_mock.chat.completions.create.call_count == 1

with patch("openai.AsyncOpenAI", return_value=openai_no_mock):
answer = await AsyncChatClient().ask_report_question(
context=report_body, question=question_body, grammar=YesNoGrammar
context=report_body, question=question_body, grammar=grammar
)

assert answer == "no"
assert answer == "No"
assert openai_no_mock.chat.completions.create.call_count == 1

close_old_connections()
12 changes: 8 additions & 4 deletions radis/chats/urls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns

from .views import (GrammarCreateView, chat_clear_all, chat_create_view,
chat_delete_view, chat_detail_view, chat_list_view,
chat_update_view)
from .views import (
chat_clear_all,
chat_create_view,
chat_delete_view,
chat_detail_view,
chat_list_view,
chat_update_view,
)

urlpatterns = [
path("", chat_list_view, name="chat_list"),
@@ -12,7 +17,6 @@
path("<int:pk>/", chat_detail_view, name="chat_detail"),
path("<int:pk>/update/", chat_update_view, name="chat_update"),
path("<int:pk>/delete/", chat_delete_view, name="chat_delete"),
path("grammars/create/", GrammarCreateView.as_view(), name="grammar_create"),
]

urlpatterns = format_suffix_patterns(urlpatterns)
8 changes: 5 additions & 3 deletions radis/chats/utils/chat_client.py
Original file line number Diff line number Diff line change
@@ -4,9 +4,11 @@

import openai
from django.conf import settings
from openai.types.chat import (ChatCompletionMessageParam,
ChatCompletionSystemMessageParam,
ChatCompletionUserMessageParam)
from openai.types.chat import (
ChatCompletionMessageParam,
ChatCompletionSystemMessageParam,
ChatCompletionUserMessageParam,
)

from radis.chats.models import Grammar

34 changes: 14 additions & 20 deletions radis/chats/views.py
Original file line number Diff line number Diff line change
@@ -3,23 +3,19 @@

from adit_radis_shared.common.decorators import login_required_async
from adit_radis_shared.common.types import AuthenticatedHttpRequest
from adit_radis_shared.common.views import LoginRequiredMixin
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import SuspiciousOperation
from django.http import HttpResponse
from django.shortcuts import (aget_object_or_404, get_object_or_404, redirect,
render)
from django.shortcuts import aget_object_or_404, get_object_or_404, redirect, render
from django.urls import reverse
from django.views.decorators.http import require_GET, require_POST
from django.views.generic import CreateView
from django_htmx.http import push_url
from django_tables2 import RequestConfig
from openai.types.chat import ChatCompletionMessageParam

from radis.chats.forms import CreateChatForm, PromptForm
from radis.chats.grammars import FreeTextGrammar, YesNoGrammar
from radis.chats.tables import ChatTable
from radis.reports.models import Report

@@ -68,27 +64,33 @@ async def chat_create_view(request: AuthenticatedHttpRequest) -> HttpResponse:

client = AsyncChatClient()

if request.POST.get("yes_no_answer"):
grammar = await Grammar.objects.aget(name="YES_NO")
else:
grammar = await Grammar.objects.aget(name="FREE_TEXT")

# Generate an answer for the user prompt
answer = await client.send_messages(
[
{"role": "system", "content": instructions_system_prompt},
{"role": "user", "content": user_prompt},
],
grammar=YesNoGrammar if request.POST.get("yes_no_answer") else FreeTextGrammar,
grammar=grammar,
)

# Generate a title for the chat
title_system_prompt = Template(settings.CHAT_GENERATE_TITLE_SYSTEM_PROMPT).substitute(
{"num_words": 6}
)

free_text_grammar = await Grammar.objects.aget(name="FREE_TEXT")
title = await client.send_messages(
[
{"role": "system", "content": title_system_prompt},
{"role": "user", "content": user_prompt},
],
max_tokens=20,
grammar=FreeTextGrammar,
grammar=free_text_grammar,
)
title = title.strip().rstrip(string.punctuation)[:100]

@@ -177,10 +179,11 @@ async def chat_update_view(request: AuthenticatedHttpRequest, pk: int) -> HttpRe
messages.append({"role": "user", "content": prompt})

client = AsyncChatClient()
response = await client.send_messages(
messages,
grammar=YesNoGrammar if request.POST.get("yes_no_answer") else FreeTextGrammar,
)
if request.POST.get("yes_no_answer"):
grammar = await Grammar.objects.aget(name="YES_NO")
else:
grammar = await Grammar.objects.aget(name="FREE_TEXT")
response = await client.send_messages(messages, grammar=grammar)

await ChatMessage.objects.acreate(chat=chat, role=ChatRole.USER, content=prompt)
await ChatMessage.objects.acreate(chat=chat, role=ChatRole.ASSISTANT, content=response)
@@ -210,12 +213,3 @@ def chat_delete_view(request: AuthenticatedHttpRequest, pk: int) -> HttpResponse

messages.add_message(request, messages.SUCCESS, "Chat deleted successfully!")
return redirect("chat_list")


class GrammarCreateView(LoginRequiredMixin, CreateView):
model = Grammar
fields = ["name", "human_readable_name", "grammar", "llm_instruction"]
template_name = "chats/_grammar_create.html"

def get_success_url(self) -> str:
return reverse("grammar_list")
7 changes: 7 additions & 0 deletions radis/conftest.py
Original file line number Diff line number Diff line change
@@ -30,3 +30,10 @@ def _openai_chat_completions_mock(content: str) -> ContextManager:
return mock_openai

return _openai_chat_completions_mock


@pytest.fixture
def default_grammars() -> None:
from radis.core.management.commands.create_default_grammars import Command

Command().handle()
29 changes: 29 additions & 0 deletions radis/core/management/commands/create_default_grammars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import time

from django.conf import settings
from django.core.management.base import BaseCommand, CommandParser
from faker import Faker

from radis.chats.models import Grammar

fake = Faker()


class Command(BaseCommand):
help = "Populates the database with default grammars."

def add_arguments(self, parser: CommandParser) -> None:
super().add_arguments(parser)

def handle(self, *args, **options):
self.stdout.write(
f"Adding {len(settings.CHAT_DEFAULT_GRAMMARS)} default grammars to the database...",
ending="",
)
self.stdout.flush()

start = time.time()
for default_grammar in settings.CHAT_DEFAULT_GRAMMARS:
default_grammar["is_default"] = True
Grammar.objects.update_or_create(name=default_grammar["name"], defaults=default_grammar)
self.stdout.write(f"Done (in {time.time() - start:.2f} seconds)")
3 changes: 1 addition & 2 deletions radis/rag/apps.py
Original file line number Diff line number Diff line change
@@ -15,8 +15,7 @@ def ready(self):


def register_app():
from adit_radis_shared.common.site import (MainMenuItem,
register_main_menu_item)
from adit_radis_shared.common.site import MainMenuItem, register_main_menu_item

register_main_menu_item(
MainMenuItem(
13 changes: 0 additions & 13 deletions radis/rag/forms.py
Original file line number Diff line number Diff line change
@@ -190,18 +190,6 @@ class Meta:
]


add_grammar_button = """
{% load bootstrap_icon from common_extras %}
<button type="button"
class="btn btn-outline-success btn-sm"
hx-get="{% url 'grammar_create' %}"
hx-target="#htmx-dialog">
{% bootstrap_icon "plus-square" %}
Add new grammar
</button>
"""


class AnalysisQuestionFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -213,7 +201,6 @@ def __init__(self, *args, **kwargs):
Div(
"question",
"grammar",
HTML(add_grammar_button),
css_class="card-body",
),
HTML(delete_button.substitute({"min_questions": "0"})),
20 changes: 20 additions & 0 deletions radis/rag/migrations/0017_alter_analysisquestion_grammar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.1.3 on 2024-12-03 12:18

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('chats', '0004_alter_grammar_name'),
('rag', '0016_alter_analysisquestion_grammar'),
]

operations = [
migrations.AlterField(
model_name='analysisquestion',
name='grammar',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='chats.grammar'),
),
]
5 changes: 1 addition & 4 deletions radis/rag/models.py
Original file line number Diff line number Diff line change
@@ -8,9 +8,6 @@
from procrastinate.contrib.django import app
from procrastinate.contrib.django.models import ProcrastinateJob

from radis.chats.grammars import (DateGrammar, DateTimeGrammar, FloatGrammar,
FreeTextGrammar, IntegerGrammar, TimeGrammar,
YesNoGrammar)
from radis.chats.models import Grammar
from radis.core.models import AnalysisJob, AnalysisTask
from radis.reports.models import Language, Modality, Report
@@ -82,7 +79,7 @@ def __str__(self) -> str:


class AnalysisQuestion(models.Model):
grammar = models.ForeignKey(Grammar, on_delete=models.CASCADE)
grammar = models.ForeignKey(Grammar, on_delete=models.SET_NULL, null=True)
question = models.CharField(max_length=500)
job = models.ForeignKey(RagJob, on_delete=models.CASCADE, related_name="analysis_questions")

15 changes: 10 additions & 5 deletions radis/rag/processors.py
Original file line number Diff line number Diff line change
@@ -6,15 +6,20 @@
from django import db
from django.conf import settings
from django.db.models import Prefetch
from regex import F

from radis.chats.models import Grammar
from radis.chats.utils.chat_client import AsyncChatClient
from radis.core.processors import AnalysisTaskProcessor

from .models import (AnalysisQuestion, AnalysisQuestionResult, Answer,
FilterQuestion, FilterQuestionResult, RagInstance,
RagTask)
from .models import (
AnalysisQuestion,
AnalysisQuestionResult,
Answer,
FilterQuestion,
FilterQuestionResult,
RagInstance,
RagTask,
)

logger = logging.getLogger(__name__)

@@ -100,7 +105,7 @@ async def process_filter_question(
context=rag_instance.text, question=question.question, grammar=yes_no_grammar
)

answer = Answer.YES if llm_answer == "yes" else Answer.NO
answer = Answer.YES if llm_answer == "Yes" else Answer.NO

result = (
RagInstance.Result.ACCEPTED
4 changes: 3 additions & 1 deletion radis/rag/tests/unit/test_processors.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,9 @@


@pytest.mark.django_db(transaction=True)
def test_rag_task_processor(create_rag_task, openai_chat_completions_mock, mocker):
def test_rag_task_processor(
create_rag_task, openai_chat_completions_mock, mocker, default_grammars
):
num_rag_instances = 5
num_questions = 5
rag_task = create_rag_task(
48 changes: 32 additions & 16 deletions radis/rag/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from typing import Any, Type, cast

from adit_radis_shared.common.mixins import (HtmxOnlyMixin,
PageSizeSelectMixin,
RelatedFilterMixin,
RelatedPaginationMixin)
from adit_radis_shared.common.mixins import (
HtmxOnlyMixin,
PageSizeSelectMixin,
RelatedFilterMixin,
RelatedPaginationMixin,
)
from adit_radis_shared.common.types import AuthenticatedHttpRequest
from django.conf import settings
from django.contrib.auth.mixins import (LoginRequiredMixin,
PermissionRequiredMixin,
UserPassesTestMixin)
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin,
UserPassesTestMixin,
)
from django.core.exceptions import SuspiciousOperation
from django.db import transaction
from django.db.models import Prefetch, QuerySet
@@ -19,22 +23,34 @@
from django_tables2 import SingleTableMixin
from formtools.wizard.views import SessionWizardView

from radis.core.views import (AnalysisJobCancelView, AnalysisJobDeleteView,
AnalysisJobDetailView, AnalysisJobListView,
AnalysisJobRestartView, AnalysisJobResumeView,
AnalysisJobRetryView, AnalysisJobVerifyView,
AnalysisTaskDeleteView, AnalysisTaskDetailView,
AnalysisTaskResetView, BaseUpdatePreferencesView)
from radis.core.views import (
AnalysisJobCancelView,
AnalysisJobDeleteView,
AnalysisJobDetailView,
AnalysisJobListView,
AnalysisJobRestartView,
AnalysisJobResumeView,
AnalysisJobRetryView,
AnalysisJobVerifyView,
AnalysisTaskDeleteView,
AnalysisTaskDetailView,
AnalysisTaskResetView,
BaseUpdatePreferencesView,
)
from radis.rag.filters import RagJobFilter, RagResultFilter, RagTaskFilter
from radis.rag.mixins import RagLockedMixin
from radis.rag.tables import RagInstanceTable, RagJobTable, RagTaskTable
from radis.reports.models import Language, Modality
from radis.search.site import Search, SearchFilters
from radis.search.utils.query_parser import QueryParser

from .forms import (AnalysisQuestionFormSet, AnalysisQuestionFormSetHelper,
FilterQuestionFormSet, FilterQuestionFormSetHelper,
SearchForm)
from .forms import (
AnalysisQuestionFormSet,
AnalysisQuestionFormSetHelper,
FilterQuestionFormSet,
FilterQuestionFormSetHelper,
SearchForm,
)
from .models import Answer, FilterQuestionResult, RagInstance, RagJob, RagTask
from .site import retrieval_providers

128 changes: 77 additions & 51 deletions radis/settings/base.py
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
"""

from pathlib import Path
from textwrap import dedent

import environ

@@ -319,57 +320,82 @@
Answer:
"""

CHAT_FREE_TEXT_GRAMMAR = None

CHAT_YES_NO_GRAMMAR = """
root ::= Answer
Answer ::= "Yes" | "No"
"""

CHAT_INT_GRAMMAR = """
root ::= Answer
Answer ::= [-]? NonZeroDigit Digit{0,18}
NonZeroDigit ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"""

CHAT_FLOAT_GRAMMAR = """
root ::= Answer
Answer ::= [-]? IntegerPart "." FractionPart
IntegerPart ::= NonZeroDigit Digit{0,7}
FractionPart ::= Digit{1,7}
NonZeroDigit ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"""

CHAT_DATE_GRAMMAR = """
root ::= Answer
Answer ::= Day "/" Month "/" Year
Day ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31"
Month ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12"
Year ::= Digit Digit Digit Digit
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
""" # noqa

CHAT_TIME_GRAMMAR = """
root ::= Answer"
Answer ::= Hour ":" Minute
Hour ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23"
Minute ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "32" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "40" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "48" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "56" | "57" | "58" | "59"
""" # noqa

CHAT_DATETIME_GRAMMAR = """
root ::= Answer
Answer ::= Date " " Time
Date ::= Day "/" Month "/" Year
Day ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31"
Month ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12"
Year ::= Digit Digit Digit Digit
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Time ::= Hour ":" Minute
Hour ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23"
Minute ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "32" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "40" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "48" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "56" | "57" | "58" | "59"
""" # noqa
CHAT_DEFAULT_GRAMMARS = [
{
"name": "YES_NO",
"human_readable_name": "Yes or No",
"grammar": dedent("""\
root ::= Answer
Answer ::= "Yes" | "No"
"""),
"llm_instruction": "Answer each question in English faithfully with 'Yes' or 'No'.",
},
{
"name": "INT",
"human_readable_name": "Integer Number",
"grammar": dedent("""\
root ::= Answer
Answer ::= [-]? NonZeroDigit Digit{0,18}
NonZeroDigit ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"""),
"llm_instruction": "Answer with an integer number.",
},
{
"name": "FLOAT",
"human_readable_name": "Floating Point Number",
"grammar": dedent("""\
root ::= Answer
Answer ::= [-]? IntegerPart "." FractionPart
IntegerPart ::= NonZeroDigit Digit{0,7}
FractionPart ::= Digit{1,7}
NonZeroDigit ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"""),
"llm_instruction": "Answer with a floating point number.",
},
{
"name": "DATE",
"human_readable_name": "Date",
"grammar": dedent("""\
root ::= Answer
Answer ::= Day "/" Month "/" Year
Day ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31"
Month ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12"
Year ::= Digit Digit Digit Digit
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"""), # noqa
"llm_instruction": "Answer with a date in format 'DD/MM/YYYY'.",
},
{
"name": "TIME",
"human_readable_name": "Time",
"grammar": dedent("""\
root ::= Answer
Answer ::= Hour ":" Minute
Hour ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23"
Minute ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "32" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "40" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "48" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "56" | "57" | "58" | "59"
"""), # noqa
"llm_instruction": "Answer with a time in format 'HH:MM'.",
},
{
"name": "DATETIME",
"human_readable_name": "Date and Time",
"grammar": dedent("""\
root ::= Answer
Answer ::= Date " " Time
Date ::= Day "/" Month "/" Year
Day ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31"
Month ::= "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12"
Year ::= Digit Digit Digit Digit
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Time ::= Hour ":" Minute
Hour ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23"
Minute ::= "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "32" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "40" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "48" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "56" | "57" | "58" | "59"
"""), # noqa
"llm_instruction": "Answer with a date and time in format 'DD/MM/YYYY HH:MM'.",
},
]


# RAG
7 changes: 4 additions & 3 deletions radis/subscriptions/processors.py
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
from django.conf import settings
from django.db.models import QuerySet

from radis.chats.grammars import YesNoGrammar
from radis.chats.models import Grammar
from radis.chats.utils.chat_client import AsyncChatClient
from radis.core.processors import AnalysisTaskProcessor
from radis.reports.models import Report
@@ -81,13 +81,14 @@ async def process_filter_question(
question: SubscriptionQuestion,
client: AsyncChatClient,
) -> RagResult:
yes_no_grammar = await Grammar.objects.aget(name="YES_NO")
llm_answer = await client.ask_report_question(
context=report_body,
question=question.question,
grammar=YesNoGrammar,
grammar=yes_no_grammar,
)

answer = Answer.YES if llm_answer == "yes" else Answer.NO
answer = Answer.YES if llm_answer == "Yes" else Answer.NO

rag_result = (
RagResult.ACCEPTED if answer == question.accepted_answer else RagResult.REJECTED