-
Notifications
You must be signed in to change notification settings - Fork 3
Subscription and Extraction Features #172
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
Open
samuelvkwong
wants to merge
127
commits into
main
Choose a base branch
from
subscription_demo
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
127 commits
Select commit
Hold shift + click to select a range
84eadf5
codex generated changes, need to review and refactor
samuelvkwong f39195d
forgotten files to stage
samuelvkwong 087e8b1
Adding downloads view
NumericalAdvantage a4a4cb2
Dont download report text
NumericalAdvantage ce4091c
adding tests
NumericalAdvantage 395cad6
linter error
NumericalAdvantage 5a85dd5
add test cases where there are no instances or extraction result has …
NumericalAdvantage 96c500a
standardize boolean values to yes/no
NumericalAdvantage 03e1841
button colrs
NumericalAdvantage 7fbe664
Merge branch 'main' into subscription_extract
samuelvkwong c631098
Merge branch 'main' into subscription_extract
samuelvkwong 9b2b368
change models
samuelvkwong 5d0cc4e
remove previous migration files
samuelvkwong 78b6c3b
fix lint errors
samuelvkwong 204ff4c
form fixes
samuelvkwong b5add39
Adding Selection output type to the existing types for extracting output
NumericalAdvantage fdf5cde
fixed subscription tests with new models
samuelvkwong 3b28ce4
Add tests for Selection form added via Alpine
NumericalAdvantage 7a2dcdb
Merge branch 'main' into subscription_extract
samuelvkwong 6292d1d
added unit test for subscriptions that use the LLM to filter/extract
samuelvkwong 197faca
match font size of legend to other elements
samuelvkwong 838cf79
fix filter question form validation
samuelvkwong b602c5f
fix dependency cycle
samuelvkwong 7410f9d
fix files that use the new renamed output_fields
samuelvkwong df06a76
complete renaming of output field
samuelvkwong 80b8293
missed one renaming, maybe use generic fk for
samuelvkwong def36f1
remove unnecessary iter
samuelvkwong da048fb
Allow middleware to detect locale from users browser (via Accept-Lang…
NumericalAdvantage eb08299
readd provider form field and use procrastinate_on_delete_sql
samuelvkwong 018d8ae
small fixes
samuelvkwong e7e6c7c
stronger form validation
samuelvkwong a67fe07
fix filter logic
samuelvkwong ed99495
rework pydantic model generation
samuelvkwong 362bfea
add more tests for subscription processor
samuelvkwong d839e58
remove redundant db query
samuelvkwong 2fc97d7
readd provider validation
samuelvkwong d726ea9
display extraction results in subscription inbox
samuelvkwong 1cbe27a
small refactors: remove has_changed, add logger, fix date for migration
samuelvkwong 8ebae98
resolve n+1 query during processing, readd empty form validator
samuelvkwong e72da19
prefetch filterquestions
samuelvkwong 6ef403a
early exit if expected_answer does not match
samuelvkwong d44453d
remove duplicate getter
samuelvkwong 69712f0
Adding option to select "array type" for the Output Field.
NumericalAdvantage 7b58df9
prevent accidental Enter from submitting the form
NumericalAdvantage db1aa5a
fixing ruff errors
NumericalAdvantage 1f3b929
move expand button above extracted fields
samuelvkwong 6b426a2
Disallow duplicate Selection Options, add test cases for the same and…
NumericalAdvantage bed99fa
Revert "Allow middleware to detect locale from users browser (via Acc…
NumericalAdvantage 1c13a0a
pagination, sorting and filtering added to inbox view
samuelvkwong 9ac799b
fix unused variables in test
samuelvkwong 323e35a
resolve invariant type checker error
samuelvkwong 2187090
linter error
NumericalAdvantage 7f52438
remove the magic number 7
NumericalAdvantage 1267257
add notification for new subscribed reports
samuelvkwong 0fe6c3e
Merge branch 'main' into subscription_extract
samuelvkwong 57b1cd9
reorder migrations from merge
samuelvkwong c4146a1
reorder subscription migrations
samuelvkwong 14656e4
migration fix
samuelvkwong 80a3ede
testing with original adit-radit-shared
samuelvkwong 9a9500b
Add selection output type with array support
NumericalAdvantage a905914
handler based approach for starting subscription jobs
samuelvkwong b6765da
Merge branch 'main' into subscription_extract
samuelvkwong cddd408
Merge branch 'subscription_extract' into subscription_handler
samuelvkwong 1c8db1c
move necessary imports inside register reports handler
samuelvkwong 417cee1
generate query from extraction fields
samuelvkwong 34a0cbc
generate query after form validation
samuelvkwong b712854
ask user for query if llm generation fails
samuelvkwong b367820
remove keyword fallback
samuelvkwong bca5fad
remove provider field from subscription detail template
samuelvkwong 3fe6fd6
resolve n+1 queries for extractions and subscriptions
samuelvkwong 5334420
narrow exception handling
samuelvkwong f9d04e0
Merge branch 'selectionOutputType' into subscription_extract
samuelvkwong 3ad21a2
remove optional from outputfield
samuelvkwong 645f64d
update extraction feature in subscriptions with new changes from ritwik
samuelvkwong 879ac15
removed query from subscriptions form
samuelvkwong cde605b
Merge remote-tracking branch 'origin/extractions' into subscription_e…
samuelvkwong ea639a4
add extractions export to subscription feature
samuelvkwong 7eb365f
Fixing form load without hidden variables error
NumericalAdvantage a228012
Merge remote-tracking branch 'origin/old-historySelectionOutput' into…
samuelvkwong ec413ad
Merge remote-tracking branch 'origin/subscription_handler' into subsc…
samuelvkwong e485427
Merge remote-tracking branch 'origin/query_generation' into subscript…
samuelvkwong 8926d04
lint fix
samuelvkwong 3d0bb32
fix attribute error for extractionjobfactory
samuelvkwong 9235cd9
fix migration order and duplicate migration
samuelvkwong 10c5ed0
fix remaining merge conflicts
samuelvkwong 77208b3
constrain autobahn (daphne dependency) to <25.11.1
samuelvkwong 335bb80
Merge remote-tracking branch 'origin/autobahn_version_constraint' int…
samuelvkwong 9903b85
fix merge issues
samuelvkwong 85fc8bd
fix syntax error
samuelvkwong 0feb599
Merge branch 'subscription_extract' into query_generation
samuelvkwong 775b9c2
swap search and extraction step in extractionjobwizard
samuelvkwong 1f07595
fix migration order
samuelvkwong b378d9b
live update report count and search link
samuelvkwong edb7adc
move live update below query and fix get request for the live update
samuelvkwong e427b1c
Merge branch 'main' into subscription_demo
samuelvkwong 0b77d3c
Merge branch 'main' into query_generation
samuelvkwong 25c21b8
Merge branch 'query_generation' into subscription_demo
samuelvkwong 61224b9
fix query generator and selection options tests
samuelvkwong 91fa5ad
move selection options js/css from core to extractions. remove extrac…
samuelvkwong 8e916fc
add error handling to chat client, remove optional from query field, …
samuelvkwong e453cad
use try finally for closing db connection in threads
samuelvkwong 54a2273
lint fix
samuelvkwong 0a4e8c8
remove error handling code smell, add transaction atomicity to subscr…
samuelvkwong 86539a1
add auto escape to protect against xss attacks
samuelvkwong 4e4d1ea
prefetch pks to avoid n+1 query during csv export
samuelvkwong d70204b
Merge branch 'main' into subscription_demo
samuelvkwong 566924f
made query generation async
samuelvkwong bb70ad4
Remove duplicate OutputFieldForm from subscriptions, import from extr…
samuelvkwong 42faad0
refactor search, extractions, subscriptions forms
samuelvkwong b7d126d
reduce code duplication in chat_client and in validating selection op…
samuelvkwong 8e26e4c
Revert subscription handling from event-driven back to periodic cron
samuelvkwong a4d569d
Subscriptions run every hour with de-duplication
samuelvkwong 4a926a5
Fix ChoiceField empty_label handling in create_language_field
samuelvkwong 5f09a15
remove unused subscription handlers
samuelvkwong be01bd9
Let Django use the prefetched cache of the table by calling all() on …
NumericalAdvantage d493c6e
Fix code quality issues from PR review
samuelvkwong 76d713f
Merge branch 'main' into subscription_demo
samuelvkwong d7a58db
update language form field factory function
samuelvkwong 1dea313
Address code review feedback for PR #172
samuelvkwong b5e4948
Add missing Previous Step button to extraction wizard Step 2
samuelvkwong 5a465b3
Fix Previous Step button validation in extraction wizard Step 2
samuelvkwong b267323
Merge branch 'main' into subscription_demo
samuelvkwong bc95cf5
Fix ThreadPoolExecutor error handling and subscription refresh timing
samuelvkwong 21a9ba9
Merge remote-tracking branch 'origin/subscription_demo' into subscrip…
samuelvkwong 827fcdb
Fix invalid query kwarg in subscription task test
samuelvkwong 5c4e6d5
Fix incorrect assertions using `and` with `not in`
samuelvkwong 9c3ab2d
Add Playwright acceptance tests for extractions and subscriptions
samuelvkwong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,7 @@ | |
| "de": "German", | ||
| "en": "English", | ||
| } | ||
|
|
||
| MIN_AGE = 0 | ||
| MAX_AGE = 120 | ||
| AGE_STEP = 10 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| """ | ||
| Reusable form field factories for RADIS forms. | ||
|
|
||
| This module provides factory functions for commonly used form fields | ||
| to reduce duplication across the codebase. | ||
| """ | ||
|
|
||
| from typing import Literal, overload | ||
|
|
||
| from django import forms | ||
|
|
||
| from radis.core.constants import AGE_STEP, LANGUAGE_LABELS, MAX_AGE, MIN_AGE | ||
| from radis.reports.models import Language, Modality | ||
|
|
||
|
|
||
| @overload | ||
| def create_language_field( | ||
| required: bool = False, | ||
| empty_label: str | None = None, | ||
| use_pk: Literal[True] = True, | ||
| ) -> forms.ModelChoiceField: ... | ||
|
|
||
|
|
||
| @overload | ||
| def create_language_field( | ||
| required: bool = False, | ||
| empty_label: str | None = None, | ||
| use_pk: Literal[False] = False, | ||
| ) -> forms.ChoiceField: ... | ||
|
|
||
|
|
||
| def create_language_field( | ||
| required: bool = False, | ||
| empty_label: str | None = None, | ||
| use_pk: bool = True, | ||
| ) -> forms.ModelChoiceField | forms.ChoiceField: | ||
| """ | ||
| Create a language choice field with consistent configuration. | ||
|
|
||
| Args: | ||
| required: Whether the field is required | ||
| empty_label: Label for empty option (None = no empty option) | ||
| use_pk: If True, returns ModelChoiceField with Language objects; | ||
| if False, returns ChoiceField with code strings | ||
|
|
||
| Returns: | ||
| ModelChoiceField (if use_pk=True) or ChoiceField (if use_pk=False) | ||
|
|
||
| Example: | ||
| # For extraction forms (uses ModelChoiceField, returns Language objects) | ||
| self.fields["language"] = create_language_field() | ||
|
|
||
| # For subscription forms (uses ModelChoiceField, allows "All") | ||
| self.fields["language"] = create_language_field(empty_label="All") | ||
|
|
||
| # For search forms (uses ChoiceField with codes) | ||
| self.fields["language"] = create_language_field(use_pk=False) | ||
| """ | ||
| languages = Language.objects.order_by("code") | ||
|
|
||
| if use_pk: | ||
| # Return ModelChoiceField - cleaned_data will contain Language objects | ||
| field = forms.ModelChoiceField( | ||
| queryset=languages, | ||
| required=required, | ||
| empty_label=empty_label, | ||
| ) | ||
| field.label_from_instance = ( # type: ignore[method-assign] | ||
| lambda obj: LANGUAGE_LABELS.get(obj.code, obj.code) | ||
| ) | ||
| return field | ||
| else: | ||
| # Return ChoiceField - cleaned_data will contain code strings | ||
| choices = [(lang.code, LANGUAGE_LABELS.get(lang.code, lang.code)) for lang in languages] | ||
| if empty_label is not None: | ||
| choices.insert(0, ("", empty_label)) | ||
| field = forms.ChoiceField(required=required, choices=choices) | ||
| return field | ||
|
|
||
|
|
||
| @overload | ||
| def create_modality_field( | ||
| required: bool = False, | ||
| widget_size: int = 6, | ||
| use_pk: Literal[True] = True, | ||
| ) -> forms.ModelMultipleChoiceField: ... | ||
|
|
||
|
|
||
| @overload | ||
| def create_modality_field( | ||
| required: bool = False, | ||
| widget_size: int = 6, | ||
| use_pk: Literal[False] = False, | ||
| ) -> forms.MultipleChoiceField: ... | ||
|
|
||
|
|
||
| def create_modality_field( | ||
| required: bool = False, | ||
| widget_size: int = 6, | ||
| use_pk: bool = True, | ||
| ) -> forms.ModelMultipleChoiceField | forms.MultipleChoiceField: | ||
| """ | ||
| Create a modality multiple choice field with consistent configuration. | ||
|
|
||
| Args: | ||
| required: Whether the field is required | ||
| widget_size: Height of the select widget | ||
| use_pk: If True, returns ModelMultipleChoiceField with Modality objects; | ||
| if False, returns MultipleChoiceField with code strings | ||
|
|
||
| Returns: | ||
| ModelMultipleChoiceField (if use_pk=True) or MultipleChoiceField (if use_pk=False) | ||
|
|
||
| Example: | ||
| # For extraction forms (uses ModelMultipleChoiceField, returns Modality objects) | ||
| self.fields["modalities"] = create_modality_field() | ||
|
|
||
| # For search forms (uses MultipleChoiceField with codes) | ||
| self.fields["modalities"] = create_modality_field(use_pk=False) | ||
| """ | ||
| modalities = Modality.objects.filter(filterable=True).order_by("code") | ||
|
|
||
| if use_pk: | ||
| # Return ModelMultipleChoiceField - cleaned_data will contain Modality objects | ||
| field = forms.ModelMultipleChoiceField( | ||
| queryset=modalities, | ||
| required=required, | ||
| ) | ||
| # Display just the code for each modality | ||
| field.label_from_instance = lambda obj: obj.code | ||
| field.widget.attrs["size"] = widget_size | ||
| return field | ||
| else: | ||
| # Return MultipleChoiceField - cleaned_data will contain code strings | ||
| field = forms.MultipleChoiceField(required=required) | ||
| field.choices = [(mod.code, mod.code) for mod in modalities] | ||
| field.widget.attrs["size"] = widget_size | ||
| return field | ||
|
|
||
|
|
||
| def create_age_range_fields() -> tuple[forms.IntegerField, forms.IntegerField]: | ||
| """ | ||
| Create age_from and age_till fields with consistent configuration. | ||
|
|
||
| Returns: | ||
| Tuple of (age_from_field, age_till_field) | ||
|
|
||
| Example: | ||
| age_from, age_till = create_age_range_fields() | ||
| self.fields["age_from"] = age_from | ||
| self.fields["age_till"] = age_till | ||
| """ | ||
| age_from = forms.IntegerField( | ||
| required=False, | ||
| min_value=MIN_AGE, | ||
| max_value=MAX_AGE, | ||
| widget=forms.NumberInput( | ||
| attrs={ | ||
| "type": "range", | ||
| "step": AGE_STEP, | ||
| "value": MIN_AGE, | ||
| } | ||
| ), | ||
| ) | ||
|
|
||
| age_till = forms.IntegerField( | ||
| required=False, | ||
| min_value=MIN_AGE, | ||
| max_value=MAX_AGE, | ||
| widget=forms.NumberInput( | ||
| attrs={ | ||
| "type": "range", | ||
| "step": AGE_STEP, | ||
| "value": MAX_AGE, | ||
| } | ||
| ), | ||
| ) | ||
|
|
||
| return age_from, age_till |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.