From c2222088794c20cd21f06da60adc1ff89786e4e5 Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Mon, 27 May 2024 15:03:38 +0200 Subject: [PATCH 1/8] :gem: check code and enforce universal conventions in html --- README.md | 2 +- tracex_project/db_results/forms.py | 18 ++- .../templates/metrics_pj_overview.html | 2 +- tracex_project/db_results/views.py | 137 ++++++++++++------ tracex_project/extraction/forms.py | 11 +- tracex_project/extraction/logic/module.py | 10 +- .../logic/modules/module_activity_labeler.py | 28 ++-- .../logic/modules/module_cohort_tagger.py | 8 +- .../modules/module_event_type_classifier.py | 4 +- .../modules/module_location_extractor.py | 4 +- .../logic/modules/module_time_extractor.py | 30 ++-- .../extraction/logic/orchestrator.py | 2 +- tracex_project/extraction/models.py | 8 +- .../templates/choose_input_method.html | 2 +- .../extraction/templates/filter_journey.html | 2 +- .../extraction/templates/journey_details.html | 2 +- .../extraction/templates/result.html | 2 +- .../extraction/templates/select_journey.html | 2 +- .../extraction/templates/upload_journey.html | 4 +- .../extraction/tests/test_orchestrator.py | 4 +- tracex_project/extraction/tests/test_views.py | 20 +-- tracex_project/extraction/views.py | 10 +- .../patient_journey_generator/apps.py | 2 +- .../patient_journey_generator/forms.py | 11 +- .../patient_journey_generator/generator.py | 14 +- .../templates/journey_generator_overview.html | 10 +- .../patient_journey_generator/views.py | 37 +++-- tracex_project/trace_comparator/forms.py | 8 +- .../trace_comparator/migrations/__init__.py | 0 .../templates/testing_overview.html | 2 +- tracex_project/trace_comparator/views.py | 8 +- tracex_project/tracex/logic/constants.py | 3 +- tracex_project/tracex/settings.py | 6 +- 33 files changed, 240 insertions(+), 173 deletions(-) delete mode 100644 tracex_project/trace_comparator/migrations/__init__.py diff --git a/README.md b/README.md index d2596a4b..364c34ff 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Key Points -This bachelorproject focuses on event log extraction from patient journeys using large-language models. +This bachelorproject focuses on event log extraction from Patient Journeys using large-language models. Our project partner is mamahealth. More information about them can be found here: [mamahealth](https://www.mamahealth.io/) diff --git a/tracex_project/db_results/forms.py b/tracex_project/db_results/forms.py index aed83ca9..ebb0a2d5 100644 --- a/tracex_project/db_results/forms.py +++ b/tracex_project/db_results/forms.py @@ -9,9 +9,11 @@ class PatientJourneySelectForm(forms.Form): - """Form for selecting a patient journey.""" + """Form for selecting a Patient Journey.""" - selected_patient_journey = forms.ChoiceField(choices=[]) + selected_patient_journey = forms.ChoiceField( + choices=[], label="Selected Patient Journey:" + ) def __init__(self, *args, **kwargs): """Initializes the PatientJourneySelectForm.""" @@ -20,10 +22,14 @@ def __init__(self, *args, **kwargs): "selected_patient_journey" ].choices = self.get_patient_journey_choices() - def get_patient_journey_choices(self) -> List[Tuple[str, str]]: - """Retrieves the available patient journey choices with existing metrics from the database.""" - patient_journeys = PatientJourney.manager.filter( - trace__events__metrics__isnull=False + @staticmethod + def get_patient_journey_choices() -> List[Tuple[str, str]]: + """Retrieves the available Patient Journey choices with existing metrics from the database.""" + patient_journeys: List[PatientJourney] = PatientJourney.manager.filter( + trace__events__metrics__isnull=False, + trace__events__metrics__activity_relevance__isnull=False, + trace__events__metrics__timestamp_correctness__isnull=False, + trace__events__metrics__correctness_confidence__isnull=False, ).distinct() choices = [(pj.name, pj.name) for pj in patient_journeys] diff --git a/tracex_project/db_results/templates/metrics_pj_overview.html b/tracex_project/db_results/templates/metrics_pj_overview.html index ce74a3c3..f1e87c27 100644 --- a/tracex_project/db_results/templates/metrics_pj_overview.html +++ b/tracex_project/db_results/templates/metrics_pj_overview.html @@ -10,7 +10,7 @@

Welcome to the Metrics Dashboard

The Metrics Dashboard is a comprehensive visual interface that displays key metrics tracked by the metrics analyzer module during the extraction of a trace.

-

Please select one patient journey for that you want to see the dashboard.

+

Please select one Patient Journey for that you want to see the dashboard.

{% csrf_token %} diff --git a/tracex_project/db_results/views.py b/tracex_project/db_results/views.py index 49ba8777..6e7c00ca 100644 --- a/tracex_project/db_results/views.py +++ b/tracex_project/db_results/views.py @@ -29,7 +29,7 @@ def get_context_data(self, **kwargs): class MetricsOverviewView(FormView): - """View for selecting a patient journey for showing metrics.""" + """View for selecting a Patient Journey for showing metrics.""" form_class = PatientJourneySelectForm template_name = "metrics_pj_overview.html" @@ -50,11 +50,11 @@ class MetricsDashboardView(TemplateView): def get_context_data(self, **kwargs): """ - Extend the existing context with additional metrics relevant to the patient journey. + Extend the existing context with additional metrics relevant to the Patient Journey. - This method retrieves the patient journey name from the session, fetches the corresponding + This method retrieves the Patient Journey name from the session, fetches the corresponding data frame, and updates the context object with various metrics and visualizations such as - counts, charts, and data tables related to the patient journey. + counts, charts, and data tables related to the Patient Journey. """ context = super().get_context_data(**kwargs) @@ -68,10 +68,10 @@ def get_context_data(self, **kwargs): def get_latest_trace_df(self) -> pd.DataFrame: """ - Fetch the DataFrame for the latest trace of a specific patient journey stored in the session. + Fetch the DataFrame for the latest trace of a specific Patient Journey stored in the session. This method constructs a query to fetch the ID of the latest trace entry related to a - patient journey. It considers only those entries where activity relevance, timestamp correctness, + Patient Journey. It considers only those entries where activity relevance, timestamp correctness, and correctness confidence metrics are not null. It then retrieves the DataFrame for these events. """ @@ -90,57 +90,86 @@ def get_latest_trace_df(self) -> pd.DataFrame: return u.DataFrameUtilities.get_events_df(query_last_trace) def update_context_with_counts(self, context, trace_df: pd.DataFrame): - """Update the given context dictionary with count statistics related to patient journeys and traces.""" + """Update the given context dictionary with count statistics related to Patient Journeys and traces.""" patient_journey_name = self.request.session["patient_journey_name"] - context.update({ - "patient_journey_name": patient_journey_name, - "total_patient_journeys": PatientJourney.manager.count(), - "total_traces": Trace.manager.count(), - "total_activities": trace_df.shape[0], - "traces_count": Trace.manager.filter(patient_journey__name=patient_journey_name).count() - }) + context.update( + { + "patient_journey_name": patient_journey_name, + "total_patient_journeys": PatientJourney.manager.count(), + "total_traces": Trace.manager.count(), + "total_activities": trace_df.shape[0], + "traces_count": Trace.manager.filter( + patient_journey__name=patient_journey_name + ).count(), + } + ) def update_context_with_charts(self, context, trace_df: pd.DataFrame): """Update the context dictionary with chart visualizations.""" relevance_counts = trace_df["activity_relevance"].value_counts() timestamp_correctness_counts = trace_df["timestamp_correctness"].value_counts() - context.update({ - "activity_relevance_pie_chart": self.create_pie_chart(relevance_counts), - "timestamp_correctness_pie_chart": self.create_pie_chart(timestamp_correctness_counts), - "activity_relevance_bar_chart": self.create_bar_chart(relevance_counts, "Activity Relevance", "Count"), - "timestamp_correctness_bar_chart": self.create_bar_chart(timestamp_correctness_counts, - "Timestamp Correctness", "Count"), - "most_frequent_category": relevance_counts.index[0], - "most_frequent_category_count": relevance_counts.values[0], - "most_frequent_timestamp_correctness": timestamp_correctness_counts.index[0], - "most_frequent_timestamp_correctness_count": timestamp_correctness_counts.values[0], - "average_timestamp_correctness": round(trace_df["correctness_confidence"].mean(), 2) - }) + context.update( + { + "activity_relevance_pie_chart": self.create_pie_chart(relevance_counts), + "timestamp_correctness_pie_chart": self.create_pie_chart( + timestamp_correctness_counts + ), + "activity_relevance_bar_chart": self.create_bar_chart( + relevance_counts, "Activity Relevance", "Count" + ), + "timestamp_correctness_bar_chart": self.create_bar_chart( + timestamp_correctness_counts, "Timestamp Correctness", "Count" + ), + "most_frequent_category": relevance_counts.index[0], + "most_frequent_category_count": relevance_counts.values[0], + "most_frequent_timestamp_correctness": timestamp_correctness_counts.index[ + 0 + ], + "most_frequent_timestamp_correctness_count": timestamp_correctness_counts.values[ + 0 + ], + "average_timestamp_correctness": round( + trace_df["correctness_confidence"].mean(), 2 + ), + } + ) def update_context_with_data_tables(self, context, trace_df: pd.DataFrame): """Format trace data into styled HTML tables and add them to the context.""" # Apply renaming, styling, and convert to HTML, then update the context relevance_columns = ["activity", "activity_relevance"] - timestamp_columns = ["activity", "time:timestamp", "time:end_timestamp", "timestamp_correctness", - "correctness_confidence"] + timestamp_columns = [ + "activity", + "time:timestamp", + "time:end_timestamp", + "timestamp_correctness", + "correctness_confidence", + ] relevance_df = trace_df[relevance_columns] relevance_df = u.Conversion.rename_columns(relevance_df) - relevance_styled = relevance_df.style.set_table_attributes('class="dataframe"').apply(self.color_relevance, - axis=1).hide().to_html() + relevance_styled = ( + relevance_df.style.set_table_attributes('class="dataframe"') + .apply(self.color_relevance, axis=1) + .hide() + .to_html() + ) timestamp_df = trace_df[timestamp_columns] timestamp_df = u.Conversion.rename_columns(timestamp_df) - timestamp_styled = timestamp_df.style.set_table_attributes('class="dataframe"').apply( - self.color_timestamp_correctness, axis=1).hide().to_html() + timestamp_styled = ( + timestamp_df.style.set_table_attributes('class="dataframe"') + .apply(self.color_timestamp_correctness, axis=1) + .hide() + .to_html() + ) - context.update({ - "relevance_df": relevance_styled, - "timestamp_df": timestamp_styled - }) + context.update( + {"relevance_df": relevance_styled, "timestamp_df": timestamp_styled} + ) @staticmethod def color_relevance(row: pd.Series) -> List[str]: @@ -169,9 +198,9 @@ def color_timestamp_correctness(row: pd.Series) -> List[str]: styles = ["background-color: tan"] * len(row) if ( - low_confidence_threshold - <= correctness_confidence - <= high_confidence_threshold + low_confidence_threshold + <= correctness_confidence + <= high_confidence_threshold ): styles[confidence_index] = "background-color: orange" elif correctness_confidence < low_confidence_threshold: @@ -244,8 +273,12 @@ def get_context_data(self, **kwargs): cohorts_df = self.get_cohorts_data(traces) if not event_log_df.empty: - event_log_df = self.filter_and_cleanup_event_log(event_log_df, filter_settings) - context.update(self.generate_dfg_and_tables(event_log_df, cohorts_df, filter_settings)) + event_log_df = self.filter_and_cleanup_event_log( + event_log_df, filter_settings + ) + context.update( + self.generate_dfg_and_tables(event_log_df, cohorts_df, filter_settings) + ) context.update({"form": EvaluationForm(initial=filter_settings)}) self.request.session["event_log"] = event_log_df.to_json() @@ -275,14 +308,20 @@ def get_traces_and_events(self) -> Tuple[QuerySet, pd.DataFrame]: def get_cohorts_data(traces: QuerySet) -> pd.DataFrame: """Extract and format cohort data from given traces for further processing and visualization.""" cohorts = Cohort.manager.filter(trace__in=traces) - cohorts_data = list(cohorts.values("trace", "age", "sex", "origin", "condition", "preexisting_condition")) + cohorts_data = list( + cohorts.values( + "trace", "age", "sex", "origin", "condition", "preexisting_condition" + ) + ) cohorts_df = pd.DataFrame(cohorts_data) if not cohorts_df.empty: cohorts_df["age"] = cohorts_df["age"].astype(pd.Int64Dtype()) return cohorts_df @staticmethod - def filter_and_cleanup_event_log(event_log_df: pd.DataFrame, filter_settings: dict) -> pd.DataFrame: + def filter_and_cleanup_event_log( + event_log_df: pd.DataFrame, filter_settings: dict + ) -> pd.DataFrame: """Apply user-defined filters to the event log data and clean up unnecessary columns.""" filter_dict = { "event_type": filter_settings.get("event_types"), @@ -290,12 +329,18 @@ def filter_and_cleanup_event_log(event_log_df: pd.DataFrame, filter_settings: di } event_log_df = u.DataFrameUtilities.filter_dataframe(event_log_df, filter_dict) event_log_df = event_log_df.drop( - columns=["activity_relevance", "timestamp_correctness", "correctness_confidence"]) + columns=[ + "activity_relevance", + "timestamp_correctness", + "correctness_confidence", + ] + ) return event_log_df @staticmethod - def generate_dfg_and_tables(event_log_df: pd.DataFrame, cohorts_df: pd.DataFrame, - filter_settings: dict) -> dict: + def generate_dfg_and_tables( + event_log_df: pd.DataFrame, cohorts_df: pd.DataFrame, filter_settings: dict + ) -> dict: """Generate visualizations and HTML tables for the provided event log and cohort data.""" activity_key = filter_settings.get("activity_key") return { diff --git a/tracex_project/extraction/forms.py b/tracex_project/extraction/forms.py index 7b3cd92e..41a3d700 100644 --- a/tracex_project/extraction/forms.py +++ b/tracex_project/extraction/forms.py @@ -9,7 +9,7 @@ class JourneyUploadForm(forms.ModelForm): - """Form for uploading your own patient journey.""" + """Form for uploading your own Patient Journey.""" class Meta: """ @@ -32,13 +32,13 @@ class Meta: } widgets = { "name": forms.TextInput( - attrs={"placeholder": "Name for your patient journey"} + attrs={"placeholder": "Name for your Patient Journey"} ), } ALLOWED_FILE_TYPES = ["txt"] file = forms.FileField( - label="Upload your patient journey", + label="Upload your Patient Journey", help_text=f"Please upload a file of type {ALLOWED_FILE_TYPES}.", required=True, ) @@ -46,10 +46,11 @@ class Meta: class JourneySelectForm(forms.Form): - """Django form for selecting a patient journey from available choices in the database.""" + """Django form for selecting a Patient Journey from available choices in the database.""" selected_patient_journey = forms.ChoiceField( choices=[], + label="Selected Patient Journey:", widget=forms.Select(attrs={"id": "patient-journey-select"}), ) @@ -62,7 +63,7 @@ def __init__(self, *args, **kwargs): @staticmethod def get_patient_journey_choices() -> List[Tuple[str, str]]: - """Returns a list of tuples containing the names of all patient journeys from the database.""" + """Returns a list of tuples containing the names of all Patient Journeys from the database.""" patient_journeys = PatientJourney.manager.all() choices = [ (patient_journey.name, patient_journey.name) diff --git a/tracex_project/extraction/logic/module.py b/tracex_project/extraction/logic/module.py index f739c81c..d876d9b5 100644 --- a/tracex_project/extraction/logic/module.py +++ b/tracex_project/extraction/logic/module.py @@ -15,7 +15,7 @@ def __init__(self): Initializes a module with the following parameters. name: The name of the module. description: A description of what the module does. - patient_journey: The patient journey most modules operate on. + patient_journey: The Patient Journey most modules operate on. result: The result that the module provides. """ self.name = None @@ -37,8 +37,8 @@ def execute( Keyword arguments: _input -- Any additional input to the module. - patient_journey -- The patient journey as text. - patient_journey_sentences -- The same patient journey as a list of sentences. + patient_journey -- The Patient Journey as text. + patient_journey_sentences -- The same Patient Journey as a list of sentences. """ self.patient_journey = patient_journey self.patient_journey_sentences = patient_journey_sentences @@ -57,8 +57,8 @@ def execute_and_save( Executes the logic of the module and saves the result to the database. Override this to define your own module. Keyword arguments: - patient_journey -- The patient journey as text. - patient_journey_sentences -- The same patient journey as a list of sentences. + patient_journey -- The Patient Journey as text. + patient_journey_sentences -- The same Patient Journey as a list of sentences. """ self.patient_journey = patient_journey self.patient_journey_sentences = patient_journey_sentences diff --git a/tracex_project/extraction/logic/modules/module_activity_labeler.py b/tracex_project/extraction/logic/modules/module_activity_labeler.py index 405fdf00..e56789bf 100644 --- a/tracex_project/extraction/logic/modules/module_activity_labeler.py +++ b/tracex_project/extraction/logic/modules/module_activity_labeler.py @@ -1,4 +1,4 @@ -"""This is the module that extracts the activity labels from the patient journey.""" +"""This is the module that extracts the activity labels from the Patient Journey.""" from pathlib import Path from typing import List, Optional import pandas as pd @@ -12,13 +12,13 @@ class ActivityLabeler(Module): """ - This is the module that starts the pipeline with structuring the patient journey in activities. + This is the module that starts the pipeline with structuring the Patient Journey in activities. """ def __init__(self): super().__init__() self.name = "Activity Labeler" - self.description = "Extracts the activity labels from a patient journey." + self.description = "Extracts the activity labels from a Patient Journey." @log_execution_time(Path(settings.BASE_DIR / "tracex/logs/execution_time.log")) def execute( @@ -29,9 +29,9 @@ def execute( cohort=None, ) -> pd.DataFrame: """ - Extracts the activity labels from the patient journey with the following steps: - 1. Number the patient journey sentences to enable selecting a specific range of sentences. - 2. Extract the activity labels from the patient journey using chatgpt. + Extracts the activity labels from the Patient Journey with the following steps: + 1. Number the Patient Journey sentences to enable selecting a specific range of sentences. + 2. Extract the activity labels from the Patient Journey using chatgpt. """ super().execute( _input, @@ -45,14 +45,16 @@ def execute( patient_journey_numbered: str = self.__number_patient_journey_sentences( patient_journey_sentences ) - activity_labels: pd.DataFrame = self.__extract_activities(patient_journey_numbered, condition) + activity_labels: pd.DataFrame = self.__extract_activities( + patient_journey_numbered, condition + ) return activity_labels @staticmethod def __number_patient_journey_sentences(patient_journey_sentences: List[str]) -> str: """ - Number the patient journey sentences as one String in the format: + Number the Patient Journey sentences as one String in the format: 1: ... 2: ... And so on. @@ -65,15 +67,17 @@ def __number_patient_journey_sentences(patient_journey_sentences: List[str]) -> return patient_journey_numbered @staticmethod - def __extract_activities(patient_journey_numbered: str, condition: Optional[str]) -> pd.DataFrame: + def __extract_activities( + patient_journey_numbered: str, condition: Optional[str] + ) -> pd.DataFrame: """ - Converts a patient journey, where every sentence is numbered, to a DataFrame with the activity labels by - extracting the activity labels from the patient journey. + Converts a Patient Journey, where every sentence is numbered, to a DataFrame with the activity labels by + extracting the activity labels from the Patient Journey. """ column_name = "activity" messages = Prompt.objects.get(name="TEXT_TO_ACTIVITY_MESSAGES").text - user_message: List[str] = patient_journey_numbered + user_message: str = patient_journey_numbered if condition is not None: user_message = f"Focus on those events that are related to the course of the disease of {condition}.\n\n\ {user_message}" diff --git a/tracex_project/extraction/logic/modules/module_cohort_tagger.py b/tracex_project/extraction/logic/modules/module_cohort_tagger.py index d461782a..551ada15 100644 --- a/tracex_project/extraction/logic/modules/module_cohort_tagger.py +++ b/tracex_project/extraction/logic/modules/module_cohort_tagger.py @@ -1,4 +1,4 @@ -"""This is the module that cohort tags from the patient journey.""" +"""This is the module that cohort tags from the Patient Journey.""" from pathlib import Path from typing import Dict, List, Optional from django.conf import settings @@ -11,14 +11,14 @@ class CohortTagger(Module): """ - This is the module that extracts the cohort information from the patient journey. + This is the module that extracts the cohort information from the Patient Journey. The cohort tags are condition, age, biological sex, origin and preexisting condition. """ def __init__(self): super().__init__() self.name = "Cohort Tagger" - self.description = "Extracts the cohort tags from a patient journey." + self.description = "Extracts the cohort tags from a Patient Journey." @log_execution_time(Path(settings.BASE_DIR / "tracex/logs/execution_time.log")) def execute_and_save( @@ -27,7 +27,7 @@ def execute_and_save( patient_journey: str = None, patient_journey_sentences: List[str] = None, ) -> Optional[Dict[str, str]]: - """Extracts the cohort information from the patient journey and saves the result in the database.""" + """Extracts the cohort information from the Patient Journey and saves the result in the database.""" super().execute_and_save( df, patient_journey=patient_journey, diff --git a/tracex_project/extraction/logic/modules/module_event_type_classifier.py b/tracex_project/extraction/logic/modules/module_event_type_classifier.py index b0b1ccab..728c3577 100644 --- a/tracex_project/extraction/logic/modules/module_event_type_classifier.py +++ b/tracex_project/extraction/logic/modules/module_event_type_classifier.py @@ -14,13 +14,13 @@ class EventTypeClassifier(Module): This module classifies the event types of the activities. The given event types are 'Symptom Onset', 'Symptom Offset', 'Diagnosis', 'Doctor visit', 'Treatment', 'Hospital admission', 'Hospital discharge', 'Medication', 'Lifestyle Change' and 'Feelings'. This is done so that we can extract a standardized set of event - types from the patient journey. This is necessary for the application of process mining algorithms. + types from the Patient Journey. This is necessary for the application of process mining algorithms. """ def __init__(self): super().__init__() self.name = "Event Type Classifier" - self.description = "Classifies the event types for the corresponding activity labels from a patient journey." + self.description = "Classifies the event types for the corresponding activity labels from a Patient Journey." @log_execution_time(Path(settings.BASE_DIR / "tracex/logs/execution_time.log")) def execute( diff --git a/tracex_project/extraction/logic/modules/module_location_extractor.py b/tracex_project/extraction/logic/modules/module_location_extractor.py index da100c8d..e9115919 100644 --- a/tracex_project/extraction/logic/modules/module_location_extractor.py +++ b/tracex_project/extraction/logic/modules/module_location_extractor.py @@ -11,14 +11,14 @@ class LocationExtractor(Module): """ - This is the module that extracts the location information from the patient journey to each activity. + This is the module that extracts the location information from the Patient Journey to each activity. This means all activities are classified to the given locations "Home", "Hospital", "Doctors". """ def __init__(self): super().__init__() self.name = "Location Extractor" - self.description = "Extracts the locations for the corresponding activity labels from a patient journey." + self.description = "Extracts the locations for the corresponding activity labels from a Patient Journey." @log_execution_time(Path(settings.BASE_DIR / "tracex/logs/execution_time.log")) def execute( diff --git a/tracex_project/extraction/logic/modules/module_time_extractor.py b/tracex_project/extraction/logic/modules/module_time_extractor.py index 91a73bbc..c8857628 100644 --- a/tracex_project/extraction/logic/modules/module_time_extractor.py +++ b/tracex_project/extraction/logic/modules/module_time_extractor.py @@ -1,4 +1,4 @@ -"""This module extracts the time information from the patient journey.""" +"""This module extracts the time information from the Patient Journey.""" from pathlib import Path from typing import List from django.conf import settings @@ -12,14 +12,14 @@ class TimeExtractor(Module): """ - This is the module that extracts the time information from the patient journey. This includes start dates, + This is the module that extracts the time information from the Patient Journey. This includes start dates, end dates and durations. """ def __init__(self): super().__init__() self.name = "Time Extractor" - self.description = "Extracts the timestamps for the corresponding activity labels from a patient journey." + self.description = "Extracts the timestamps for the corresponding activity labels from a Patient Journey." @log_execution_time(Path(settings.BASE_DIR / "tracex/logs/execution_time.log")) def execute( @@ -29,7 +29,7 @@ def execute( patient_journey_sentences: List[str] = None, cohort=None, ) -> pd.DataFrame: - """This function extracts the time information from the patient journey. + """This function extracts the time information from the Patient Journey. For each activity label, the start date, end date and duration are extracted.""" super().execute( df, @@ -100,23 +100,23 @@ def __calculate_duration(row: pd.Series) -> str: def __post_processing(df: pd.DataFrame) -> pd.DataFrame: """Fill missing values for dates with default values.""" - def convert_to_datetime(df: pd.DataFrame, column: pd.Series) -> pd.DataFrame: - df[column] = pd.to_datetime( - df[column], format="%Y%m%dT%H%M", errors="coerce" + def convert_to_datetime(_df: pd.DataFrame, column: str) -> pd.DataFrame: + _df[column] = pd.to_datetime( + _df[column], format="%Y%m%dT%H%M", errors="coerce" ) - return df + return _df - def set_default_date_if_na(df: pd.DataFrame, column: pd.Series) -> pd.DataFrame: - if df[column].isna().all(): - df[column] = df[column].fillna(pd.Timestamp("2020-01-01 00:00")) + def set_default_date_if_na(_df: pd.DataFrame, column: str) -> pd.DataFrame: + if _df[column].isna().all(): + _df[column] = _df[column].fillna(pd.Timestamp("2020-01-01 00:00")) - return df + return _df - def fill_missing_values(df: pd.DataFrame, column: pd.Series) -> pd.DataFrame: - df[column] = df[column].ffill().bfill() + def fill_missing_values(_df: pd.DataFrame, column: str) -> pd.DataFrame: + _df[column] = _df[column].ffill().bfill() - return df + return _df def fix_end_dates(row: pd.Series) -> pd.Series: if ( diff --git a/tracex_project/extraction/logic/orchestrator.py b/tracex_project/extraction/logic/orchestrator.py index da4c5891..d94c6332 100644 --- a/tracex_project/extraction/logic/orchestrator.py +++ b/tracex_project/extraction/logic/orchestrator.py @@ -29,7 +29,7 @@ class ExtractionConfiguration: """ Dataclass for the configuration of the orchestrator. This specifies all modules that can be executed, what event types are used to classify the activity labels, what locations are used to classify the activity labels and what the - patient journey is, on which the pipeline is executed. + Patient Journey is, on which the pipeline is executed. Public Methods: update -- Update the configuration with a dictionary mapping its attributes to new values. diff --git a/tracex_project/extraction/models.py b/tracex_project/extraction/models.py index ac551acb..e935b28b 100644 --- a/tracex_project/extraction/models.py +++ b/tracex_project/extraction/models.py @@ -5,11 +5,11 @@ class PatientJourney(models.Model): - """Model for the patient journey input.""" + """Model for the Patient Journey input.""" name = models.CharField( max_length=100, - help_text="The name represents a unique title describing the content of the patient journey.", + help_text="The name represents a unique title describing the content of the Patient Journey.", unique=True, ) patient_journey = models.TextField() @@ -20,7 +20,7 @@ def __str__(self): class Trace(models.Model): - """Model for the trace of a patient journey.""" + """Model for the trace of a Patient Journey.""" patient_journey = models.ForeignKey( PatientJourney, on_delete=models.CASCADE, related_name="trace" @@ -33,7 +33,7 @@ def __str__(self): class Cohort(models.Model): - """Model for the cohort of a patient journey.""" + """Model for the cohort of a Patient Journey.""" trace = models.OneToOneField( Trace, on_delete=models.CASCADE, related_name="cohort", null=True diff --git a/tracex_project/extraction/templates/choose_input_method.html b/tracex_project/extraction/templates/choose_input_method.html index 9540cd63..7da83db8 100644 --- a/tracex_project/extraction/templates/choose_input_method.html +++ b/tracex_project/extraction/templates/choose_input_method.html @@ -12,7 +12,7 @@

Choose Input Method

-

You can either upload a patient journey or select an existing patient journey from the database.

+

You can either upload a Patient Journey or select an existing Patient Journey from the database.

diff --git a/tracex_project/extraction/templates/filter_journey.html b/tracex_project/extraction/templates/filter_journey.html index d1337db5..991ed348 100644 --- a/tracex_project/extraction/templates/filter_journey.html +++ b/tracex_project/extraction/templates/filter_journey.html @@ -332,7 +332,7 @@

DFG activity key

- + diff --git a/tracex_project/extraction/templates/journey_details.html b/tracex_project/extraction/templates/journey_details.html index 70fd9da8..c19a6ae0 100644 --- a/tracex_project/extraction/templates/journey_details.html +++ b/tracex_project/extraction/templates/journey_details.html @@ -17,7 +17,7 @@

Content of "{{ patient_journey.name }}"

- + diff --git a/tracex_project/extraction/templates/result.html b/tracex_project/extraction/templates/result.html index 7a5f4fb7..e0dfead8 100644 --- a/tracex_project/extraction/templates/result.html +++ b/tracex_project/extraction/templates/result.html @@ -11,7 +11,7 @@

Success! The TracEX pipeline produced the following results:

-

This is the patient journey you provided:

+

This is the Patient Journey you provided:

{{ journey }}

diff --git a/tracex_project/extraction/templates/select_journey.html b/tracex_project/extraction/templates/select_journey.html index 8106cd99..703a0527 100644 --- a/tracex_project/extraction/templates/select_journey.html +++ b/tracex_project/extraction/templates/select_journey.html @@ -10,7 +10,7 @@

Select Patient Journey from Database

-

Please select a patient journey from the database below.

+

Please select a Patient Journey from the database below.

{% csrf_token %} diff --git a/tracex_project/extraction/templates/upload_journey.html b/tracex_project/extraction/templates/upload_journey.html index 52afa4ff..f79a204b 100644 --- a/tracex_project/extraction/templates/upload_journey.html +++ b/tracex_project/extraction/templates/upload_journey.html @@ -9,7 +9,7 @@

Upload Patient Journey

-

Please select the patient journey you want to upload below.

+

Please select the Patient Journey you want to upload below.

{% csrf_token %} @@ -35,6 +35,6 @@

Upload Patient Journey

- + diff --git a/tracex_project/extraction/tests/test_orchestrator.py b/tracex_project/extraction/tests/test_orchestrator.py index 1955713e..305b7a3e 100644 --- a/tracex_project/extraction/tests/test_orchestrator.py +++ b/tracex_project/extraction/tests/test_orchestrator.py @@ -109,11 +109,11 @@ def test_initialize_modules(self): def test_run(self): """Test if the run method correctly returns a dataframe. Execution of ActivityLabeler, CohortTagger and - Preprocessor is necessary since the run method makes assumptions on how the patient journey looks like. + Preprocessor is necessary since the run method makes assumptions on how the Patient Journey looks like. """ Orchestrator.reset_instance() configuration = ExtractionConfiguration( - patient_journey="This is a test patient journey. This is some description about how I fell ill and " + patient_journey="This is a test Patient Journey. This is some description about how I fell ill and " "recovered in the end.", ) configuration.update( diff --git a/tracex_project/extraction/tests/test_views.py b/tracex_project/extraction/tests/test_views.py index 9b3c3e4e..383b2baa 100644 --- a/tracex_project/extraction/tests/test_views.py +++ b/tracex_project/extraction/tests/test_views.py @@ -101,7 +101,7 @@ def test_view_post_valid_form(self): Test that posting a valid form with a file upload successfully creates a new model instance with the uploaded content and redirects to the correct success URL. """ - file_content = "This is a test patient journey." + file_content = "This is a test Patient Journey." uploaded_file = SimpleUploadedFile("test.txt", file_content.encode("utf-8")) form_data = {"name": "Test Journey", "file": uploaded_file} @@ -168,10 +168,10 @@ def test_view_context_data(self): def test_view_post_valid_form(self): """ - Test that posting a valid form by selecting an existing patient journey redirects to the correct success URL. + Test that posting a valid form by selecting an existing Patient Journey redirects to the correct success URL. """ mock_journey = PatientJourney.manager.create( - name="Test Journey", patient_journey="This is a test patient journey." + name="Test Journey", patient_journey="This is a test Patient Journey." ) form_data = {"selected_patient_journey": mock_journey.name} response = self.client.post(self.url, data=form_data, format="multipart") @@ -203,10 +203,10 @@ class JourneyDetailViewTests(TestCase): """Test cases for the JourneyDetailView.""" def setUp(self): # pylint: disable=invalid-name - """Set up test client, a mock patient journey and the URL.""" + """Set up test client, a mock Patient Journey and the URL.""" self.client = Client() self.mock_journey = PatientJourney.manager.create( - name="Test Journey", patient_journey="This is a test patient journey." + name="Test Journey", patient_journey="This is a test Patient Journey." ) self.url = reverse("journey_details", kwargs={"pk": self.mock_journey.pk}) @@ -235,7 +235,7 @@ def test_view_context_data(self): ) def test_view_without_patient_journey(self): - """Test that requesting a patient journey that does not exist returns a 404 error.""" + """Test that requesting a Patient Journey that does not exist returns a 404 error.""" response = self.client.get(reverse("journey_details", kwargs={"pk": 999})) self.assertEqual(response.status_code, 404) @@ -263,10 +263,10 @@ class JourneyFilterViewTests(TestCase): fixtures = ["tracex_project/extraction/fixtures/prompts_fixture.json"] def setUp(self): # pylint: disable=invalid-name - """Set up test client, a mock patient journey, the URL and a factory that sends requests to the view.""" + """Set up test client, a mock Patient Journey, the URL and a factory that sends requests to the view.""" self.client = Client() self.mock_journey = PatientJourney.manager.create( - name="Test Journey", patient_journey="This is a test patient journey." + name="Test Journey", patient_journey="This is a test Patient Journey." ) self.url = reverse("journey_filter") self.factory = RequestFactory() @@ -346,10 +346,10 @@ class ResultViewTests(TestCase): fixtures = ["tracex_project/tracex/fixtures/dataframe_fixtures.json"] def setUp(self): # pylint: disable=invalid-name - """Set up test client, a mock patient journey, session data and the URL.""" + """Set up test client, a mock Patient Journey, session data and the URL.""" self.client = Client() self.mock_journey = PatientJourney.manager.create( - name="Test Journey", patient_journey="This is a test patient journey." + name="Test Journey", patient_journey="This is a test Patient Journey." ) self.session = self.client.session self.session["selected_modules"] = ["activity_labeling", "cohort_tagging"] diff --git a/tracex_project/extraction/views.py b/tracex_project/extraction/views.py index eca6d05f..b9524100 100644 --- a/tracex_project/extraction/views.py +++ b/tracex_project/extraction/views.py @@ -28,13 +28,13 @@ class JourneyInputSelectView(generic.TemplateView): - """A Django view that renders a template for the user to choose the patient journey input method.""" + """A Django view that renders a template for the user to choose the Patient Journey input method.""" template_name = "choose_input_method.html" class JourneyUploadView(generic.CreateView): - """A Django view that handles the uploading of a patient journey.""" + """A Django view that handles the uploading of a Patient Journey.""" form_class = JourneyUploadForm template_name = "upload_journey.html" @@ -55,7 +55,7 @@ def get_success_url(self): class JourneySelectView(generic.FormView): - """A Django view that handles the selection of a patient journey from the database.""" + """A Django view that handles the selection of a Patient Journey from the database.""" model = PatientJourney form_class = JourneySelectForm @@ -71,13 +71,13 @@ def form_valid(self, form): class JourneyDetailView(generic.DetailView): - """A Django view that displays the details of a selected patient journey.""" + """A Django view that displays the details of a selected Patient Journey.""" model = PatientJourney template_name = "journey_details.html" def get_context_data(self, **kwargs): - """Overrides the get_context_data method to add the patient journey to the context data.""" + """Overrides the get_context_data method to add the Patient Journey to the context data.""" context = super().get_context_data(**kwargs) patient_journey = self.get_object() context["patient_journey"] = patient_journey diff --git a/tracex_project/patient_journey_generator/apps.py b/tracex_project/patient_journey_generator/apps.py index 3280e08c..4e81b3bc 100644 --- a/tracex_project/patient_journey_generator/apps.py +++ b/tracex_project/patient_journey_generator/apps.py @@ -1,4 +1,4 @@ -"""App configuration for patient journey generator app.""" +"""App configuration for Patient Journey generator app.""" from django.apps import AppConfig diff --git a/tracex_project/patient_journey_generator/forms.py b/tracex_project/patient_journey_generator/forms.py index 3a9a9372..8344e84c 100644 --- a/tracex_project/patient_journey_generator/forms.py +++ b/tracex_project/patient_journey_generator/forms.py @@ -1,13 +1,13 @@ -"""Implementation of forms for the patient journey generator app.""" +"""Implementation of forms for the Patient Journey generator app.""" from django import forms from extraction.models import PatientJourney class GenerationOverviewForm(forms.ModelForm): """ - Form for generating a patient journey. + Form for generating a Patient Journey. - By submitting this form, a patient journey is generated and saved in the orchestrator's configuration. + By submitting this form, a Patient Journey is generated and saved in the orchestrator's configuration. """ class Meta: @@ -19,8 +19,9 @@ class Meta: fields -- The fields to include in the form. help_texts -- The help texts for the fields. widgets -- The widgets for the fields. - - "name" - A text input field to name the patient journey. Required, to save patient journey in the database. + - "name" - A text input field to name the Patient Journey. Required, to save Patient Journey in the database. """ + model = PatientJourney fields = ["name"] help_texts = { @@ -28,6 +29,6 @@ class Meta: } widgets = { "name": forms.TextInput( - attrs={"placeholder": "Name for your patient journey"} + attrs={"placeholder": "Name for your Patient Journey"} ), } diff --git a/tracex_project/patient_journey_generator/generator.py b/tracex_project/patient_journey_generator/generator.py index 433639f3..1bf0d36e 100644 --- a/tracex_project/patient_journey_generator/generator.py +++ b/tracex_project/patient_journey_generator/generator.py @@ -1,12 +1,12 @@ """ -Provides functionality to generate a synthetic patient journey by using the OpenAI API. +Provides functionality to generate a synthetic Patient Journey by using the OpenAI API. Functions: -generate_patient_journey -- Generates a synthetic patient journey. -create_patient_journey_context -- Creates a context for the synthetic patient journey. +generate_patient_journey -- Generates a synthetic Patient Journey. +create_patient_journey_context -- Creates a context for the synthetic Patient Journey. get_country -- Randomizes a european country. -get_date -- Randomizes a start date for the synthetic patient journey. -get_life_circumstances -- Generates life circumstances for the synthetic patient journey. +get_date -- Randomizes a start date for the synthetic Patient Journey. +get_life_circumstances -- Generates life circumstances for the synthetic Patient Journey. """ from datetime import datetime, timedelta import random @@ -17,7 +17,7 @@ def generate_patient_journey(): - """Generate a synthetic patient journey.""" + """Generate a synthetic Patient Journey.""" messages = Prompt.objects.get(name="CREATE_PATIENT_JOURNEY").text messages.insert(0, {"role": "system", "content": create_patient_journey_context()}) patient_journey = u.query_gpt(messages=messages, temperature=1) @@ -27,7 +27,7 @@ def generate_patient_journey(): def create_patient_journey_context(): """ - Create a context for the patient journey. + Create a context for the Patient Journey. The context includes a random sex, country, date and life circumstances. """ diff --git a/tracex_project/patient_journey_generator/templates/journey_generator_overview.html b/tracex_project/patient_journey_generator/templates/journey_generator_overview.html index c60d653d..fdd25b36 100644 --- a/tracex_project/patient_journey_generator/templates/journey_generator_overview.html +++ b/tracex_project/patient_journey_generator/templates/journey_generator_overview.html @@ -1,12 +1,12 @@ @@ -23,7 +23,7 @@
{% if generated_journey %} -

Generated Journey

+

Generated Patient Journey

{{ generated_journey }}

@@ -47,7 +47,7 @@

Generated Journey

- + {% else %} @@ -60,7 +60,7 @@

Welcome to the Patient Journey Generator of TracEX

{% endif %} - + diff --git a/tracex_project/patient_journey_generator/views.py b/tracex_project/patient_journey_generator/views.py index 364b4f5b..4d4647d8 100644 --- a/tracex_project/patient_journey_generator/views.py +++ b/tracex_project/patient_journey_generator/views.py @@ -1,9 +1,9 @@ """ -Provide class-based views for the patient journey generator app. +Provide class-based views for the Patient Journey generator app. Views: -JourneyGeneratorOverviewView -- View for the landing page of the patient journey generator. -JourneyGenerationView -- View to inspect the generated patient journey. +JourneyGeneratorOverviewView -- View for the landing page of the Patient Journey generator. +JourneyGenerationView -- View to inspect the generated Patient Journey. """ import traceback @@ -18,9 +18,9 @@ class JourneyGeneratorOverviewView(generic.CreateView): """ - View for the landing page of the patient journey generator. + View for the landing page of the Patient Journey generator. - If a generated patient journey exists in the session, this view displays a form to name the patient journey + If a generated Patient Journey exists in the session, this view displays a form to name the Patient Journey and save it in the database. """ @@ -29,14 +29,14 @@ class JourneyGeneratorOverviewView(generic.CreateView): success_url = reverse_lazy("journey_filter") def get_context_data(self, **kwargs): - """Add the patient journey to the context to pass to the HTML file.""" + """Add the Patient Journey to the context to pass to the HTML file.""" context = super().get_context_data(**kwargs) context["generated_journey"] = self.request.session.get("generated_journey") return context def form_valid(self, form): - """Create an empty patient journey instance and save the ID in the orchestrator.""" + """Create an empty Patient Journey instance and save the ID in the orchestrator.""" orchestrator = Orchestrator.get_instance() form.instance.patient_journey = orchestrator.get_configuration().patient_journey response = super().form_valid(form) @@ -47,9 +47,9 @@ def form_valid(self, form): class JourneyGenerationView(generic.RedirectView): """ - View to inspect the generated patient journey. + View to inspect the generated Patient Journey. - By passing a GET request to the view, a patient journey is generated and saved in the orchestrator's configuration. + By passing a GET request to the view, a Patient Journey is generated and saved in the orchestrator's configuration. Since the JourneyGenerationView is a RedirectView, the user is redirected back to the JourneyGeneratorOverviewView. Therefore, this view does not render a template. """ @@ -58,17 +58,19 @@ class JourneyGenerationView(generic.RedirectView): def get(self, request, *args, **kwargs): """ - Handle GET requests by generating a patient journey and updating the orchestrator's configuration. + Handle GET requests by generating a Patient Journey and updating the orchestrator's configuration. - The empty patient journey instance from the orchestrator's configuration is modified to contain the generated - patient journey text. The generated patient journey is also saved in the session to pass to the HTML file + The empty Patient Journey instance from the orchestrator's configuration is modified to contain the generated + Patient Journey text. The generated Patient Journey is also saved in the session to pass to the HTML file of the JourneyGenerationOverviewView. """ orchestrator = Orchestrator() try: - configuration = ExtractionConfiguration(patient_journey=generate_patient_journey()) + configuration = ExtractionConfiguration( + patient_journey=generate_patient_journey() + ) except Exception as e: # pylint: disable=broad-except orchestrator.reset_instance() self.request.session.flush() @@ -76,10 +78,15 @@ def get(self, request, *args, **kwargs): return render( self.request, "error_page.html", - {"error_type": type(e).__name__, "error_traceback": traceback.format_exc()} + { + "error_type": type(e).__name__, + "error_traceback": traceback.format_exc(), + }, ) orchestrator.set_configuration(configuration) - request.session["generated_journey"] = orchestrator.get_configuration().patient_journey + request.session[ + "generated_journey" + ] = orchestrator.get_configuration().patient_journey return super().get(request, *args, **kwargs) diff --git a/tracex_project/trace_comparator/forms.py b/tracex_project/trace_comparator/forms.py index 955297b6..df8cb18f 100644 --- a/tracex_project/trace_comparator/forms.py +++ b/tracex_project/trace_comparator/forms.py @@ -6,9 +6,11 @@ class PatientJourneySelectForm(forms.Form): - """Form for selecting a patient journey to use in the trace testing environment.""" + """Form for selecting a Patient Journey to use in the trace testing environment.""" - selected_patient_journey = forms.ChoiceField(choices=[]) + selected_patient_journey = forms.ChoiceField( + choices=[], label="Selected Patient Journey:" + ) def __init__(self, *args, **kwargs): """Initializes the PatientJourneySelectForm with available choices.""" @@ -19,7 +21,7 @@ def __init__(self, *args, **kwargs): @staticmethod def get_patient_journey_choices() -> List[Tuple[str, str]]: - """Retrieves the available patient journey choices from the database. Available choices are those with a + """Retrieves the available Patient Journey choices from the database. Available choices are those with a saved ground truth.""" patient_journeys = PatientJourney.manager.filter( name__contains="journey_comparison_" diff --git a/tracex_project/trace_comparator/migrations/__init__.py b/tracex_project/trace_comparator/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tracex_project/trace_comparator/templates/testing_overview.html b/tracex_project/trace_comparator/templates/testing_overview.html index 2acb1e3b..e26983b7 100644 --- a/tracex_project/trace_comparator/templates/testing_overview.html +++ b/tracex_project/trace_comparator/templates/testing_overview.html @@ -9,7 +9,7 @@

Welcome to the Trace Testing Environment

The Trace Testing Environment is a tool that enables you to assess the effectiveness of your current prompts by comparing the results of the extraction pipeline against a manually created trace, which serves as a predefined groundtruth.

-

Please select one patient journey as ground truth to compare it against the extraction pipeline result.

+

Please select one Patient Journey as ground truth to compare it against the extraction pipeline result.

{% csrf_token %} diff --git a/tracex_project/trace_comparator/views.py b/tracex_project/trace_comparator/views.py index 32f314dc..cf5fa7ce 100644 --- a/tracex_project/trace_comparator/views.py +++ b/tracex_project/trace_comparator/views.py @@ -25,7 +25,7 @@ class TraceComparisonMixin(View): def get_first_and_last_trace( patient_journey_name: str, ) -> Tuple[pd.DataFrame, pd.DataFrame]: - """Get the first and last trace of a patient journey from the database.""" + """Get the first and last trace of a Patient Journey from the database.""" query_last_trace = Q( id=Trace.manager.filter(patient_journey__name=patient_journey_name) .latest("last_modified") @@ -45,7 +45,7 @@ def get_first_and_last_trace( class TraceTestingOverviewView(FormView): - """View for selecting a patient journey to use in the Trace Testing Environment.""" + """View for selecting a Patient Journey to use in the Trace Testing Environment.""" form_class = PatientJourneySelectForm template_name = "testing_overview.html" @@ -72,7 +72,7 @@ class TraceTestingComparisonView(TemplateView, TraceComparisonMixin): template_name = "testing_comparison.html" def get_context_data(self, **kwargs): - """Prepare the latest trace of the selected patient journey that is available in the database for display.""" + """Prepare the latest trace of the selected Patient Journey that is available in the database for display.""" context = super().get_context_data(**kwargs) patient_journey_name: str = self.request.session.get("patient_journey_name") patient_journey: str = PatientJourney.manager.get( @@ -114,7 +114,7 @@ def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def post(self, request): - """Compare the newest trace of a patient journey against the ground truth and update session with results.""" + """Compare the newest trace of a Patient Journey against the ground truth and update session with results.""" patient_journey_name: str = self.request.session.get("patient_journey_name") ground_truth_df, pipeline_df = self.get_first_and_last_trace( patient_journey_name diff --git a/tracex_project/tracex/logic/constants.py b/tracex_project/tracex/logic/constants.py index adde72a4..881fe347 100644 --- a/tracex_project/tracex/logic/constants.py +++ b/tracex_project/tracex/logic/constants.py @@ -25,6 +25,7 @@ MAX_TOKENS: Final = 1100 MODEL: Final = "gpt-3.5-turbo" OAIK: Final = os.environ.get("OPENAI_API_KEY") +DJANGO_SECRET_KEY: Final = os.environ.get("DJANGO_SECRET_KEY") TEMPERATURE_SUMMARIZING: Final = 0 TEMPERATURE_CREATION: Final = 1 THRESHOLD_FOR_MATCH: Final = 0.5 @@ -117,7 +118,7 @@ ] MODULES_REQUIRED: Final = [ ("activity_labeling", "Activity Labeler"), - ("cohort_tagging", "Cohort Tagger") + ("cohort_tagging", "Cohort Tagger"), ] SNOMED_CT_API_URL = ( "https://browser.ihtsdotools.org/snowstorm/snomed-ct/browser/MAIN/descriptions" diff --git a/tracex_project/tracex/settings.py b/tracex_project/tracex/settings.py index f76e7bca..b360e9a9 100644 --- a/tracex_project/tracex/settings.py +++ b/tracex_project/tracex/settings.py @@ -12,6 +12,8 @@ from pathlib import Path +from tracex.logic import constants as c + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -19,13 +21,11 @@ # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ -# SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = "django-insecure-$u00r=^xd*m1ggjgzwj%2o2$h=34k358#imaxe22w@stk_aptt" -# SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["*"] # Application definition From 71fe9ead36deb3338ae8d6367c2d5241633218f2 Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Mon, 27 May 2024 15:08:32 +0200 Subject: [PATCH 2/8] :fire: fix dataframe fixture --- .../tracex/fixtures/dataframe_fixtures.json | Bin 307167 -> 307166 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tracex_project/tracex/fixtures/dataframe_fixtures.json b/tracex_project/tracex/fixtures/dataframe_fixtures.json index 4ef4d1849f8aef083c034ed3e19605552073ab9e..fccef76f7cb0bf31c6d0c425e357672687090c3c 100644 GIT binary patch delta 17 ZcmcbAU+CU_p@tU57N!>FEiCue0{~5W2loH~ delta 19 bcmcb2U+DgQp@tU57N!>FEiCueGjag{U2zBk From c80da4df6af86de37a28c78e1eb5077a2a8c6c6a Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Mon, 27 May 2024 15:53:56 +0200 Subject: [PATCH 3/8] :gem: fix tests --- .../extraction/fixtures/prompts_fixture.json | 1836 +++++++++-------- .../logic/modules/module_activity_labeler.py | 12 +- .../extraction/tests/test_orchestrator.py | 1 - tracex_project/extraction/tests/test_views.py | 88 - .../tracex/fixtures/dataframe_fixtures.json | Bin 307166 -> 158172 bytes tracex_project/tracex/settings.py | 2 - 6 files changed, 1015 insertions(+), 924 deletions(-) diff --git a/tracex_project/extraction/fixtures/prompts_fixture.json b/tracex_project/extraction/fixtures/prompts_fixture.json index d019d880..31b3b57d 100644 --- a/tracex_project/extraction/fixtures/prompts_fixture.json +++ b/tracex_project/extraction/fixtures/prompts_fixture.json @@ -1,897 +1,1073 @@ [ - { +{ "model": "extraction.prompt", "pk": 1, "fields": { - "name": "TEXT_TO_ACTIVITY_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text understanding and summarization. Your Job is to take a given text about an illness and convert it into bullet points regarding all important points about the course of the disease. Do not include time dates and use a miximum of 6 words per bullet point. Include the number of the sentence in the text from which you take the bullet point. The related numbers are in front of the sentences. Only include ONE sentence number per bullet point!" - }, - { - "role": "user", - "content": "1: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever.\n2: Four days later I went to the doctor and got tested positive for Covid19.\n3: Then I got hospitalized for two weeks." - }, - { - "role": "assistant", - "content": "starting to experience symptoms #1\nvisiting doctor's #2\ntesting positive for Covid19 #2\ngetting admissioned to hospital #3\ngetting discharged from hospital #3" - }, - { - "role": "user", - "content": "8: Concerned about my condition, I contacted my primary care physician via phone.\n9: He advised me to monitor my symptoms and stay at home unless they became severe." - }, - { - "role": "assistant", - "content": "contacting primary care physician #8\nmonitoring symptoms at home #9" - }, - { - "role": "user", - "content": "5: First symptoms on 01/04/2020" - }, - { - "role": "assistant", - "content": "starting to experience symptoms #5" - }, - { - "role": "user", - "content": "1: On July 15, 2022, I started experiencing the first symptoms of Covid-19 for five days.\n2: Initially, I had a mild cough and fatigue." - }, - { - "role": "assistant", - "content": "starting to experience symptoms #1\nending to experience symptoms #1" - } - ] + "name": "TEXT_TO_ACTIVITY_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text understanding and summarization. Your Job is to take a given text about a person's course of disease and to convert it into bullet points. If you are asked to focus on a specific condition, follow these steps: First think about which events are typically present in a course of disease with the condition. Then scan the text and determine which of the events you find are relevant to the condition. Finally, summarize only the relevant events in bullet points. Do not include timestamps and use a maximum of 6 words per bullet point. Include the number of the sentence in the text from which you take the bullet point at the end of the sentence, like this '#number'. The related numbers are in front of the sentences." + }, + { + "role": "user", + "content": "Focus on those events that are related to the course of the disease of Covid-19.\n\n1: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever.\n2: Four days later I went to the doctor and got tested positive for Covid-19.\n3: Then I got hospitalized for two weeks." + }, + { + "role": "assistant", + "content": "starting to experience symptoms #1\nvisiting doctor's #2\ntesting positive for Covid-19 #2\ngetting admitted to hospital #3\ngetting discharged from hospital #3" + }, + { + "role": "user", + "content": "8: Concerned about my condition, I contacted my primary care physician via phone.\n9: He advised me to monitor my symptoms and stay at home unless they became severe." + }, + { + "role": "assistant", + "content": "contacting primary care physician #8\nmonitoring symptoms at home #9" + }, + { + "role": "user", + "content": "5: First symptoms on 01/04/2020" + }, + { + "role": "assistant", + "content": "starting to experience symptoms #5" + }, + { + "role": "user", + "content": "Focus on those events that are related to the course of the disease of Covid-19.\n\n1: On July 15, 2022, I started experiencing the first symptoms of Covid-19 for five days.\n2: Initially, I had a mild cough and fatigue." + }, + { + "role": "assistant", + "content": "starting to experience symptoms #1\nending to experience symptoms #1" + }, + { + "role": "user", + "content": "5:After surviving Covid-19, I made getting vaccinated a top priority. 6: I received my first dose of the vaccine in early February 2022 and the second dose three weeks later. 7: Despite the challenges I faced during my infection, I remained determined to protect myself and others from the virus by getting vaccinated." + }, + { + "role": "assistant", + "content": "receiving first dose of vaccine #6\nreceiving second dose of vaccine #6" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 2, "fields": { - "name": "START_DATE_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text and a given activity label and to extract a start date to this activity label. Only output the extracted start date! Rely also on the context." - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: experiencing mild symptoms" - }, - { - "role": "assistant", - "content": "20200401T0000" - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: testing positive for Covid19" - }, - { - "role": "assistant", - "content": "20200405T0000" - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: getting infected again" - }, - { - "role": "assistant", - "content": "20200601T0000" - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: having back pain" - }, - { - "role": "assistant", - "content": "N/A" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms" - }, - { - "role": "assistant", - "content": "20210701T0000" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing side effects of vaccination" - }, - { - "role": "assistant", - "content": "20211104T0000" - } - ] + "name": "START_DATE_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text and a given activity label and to extract a start date to this activity label. The text might contain timestamps in the format --YYYYMM/DD--, with two hyphens enclosing the date. Only use these timestamps as backup, in case no other time information is available. Only output the extracted start date! Rely on the context to determine the start date, as it might not be explicitly mentioned." + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever --2020/04/01--. Four days later I went to the doctor and got tested positive for Covid19--2020/04/01--. In June I got infected again--2020/04/01--. After that I had a back pain--2020/04/01--.\nActivity Label: experiencing mild symptoms" + }, + { + "role": "assistant", + "content": "20200401T0000" + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever --2020/04/01--. Four days later I went to the doctor and got tested positive for Covid19--2020/04/01--. In June I got infected again--2020/04/01--. After that I had a back pain--2020/04/01--.\nActivity Label: testing positive for Covid19" + }, + { + "role": "assistant", + "content": "20200405T0000" + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: getting infected again" + }, + { + "role": "assistant", + "content": "20200601T0000" + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: having back pain" + }, + { + "role": "assistant", + "content": "N/A" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21--2021/07/01--. I then got tested positive for Covid19--2021/07/01--. In October I got infected again--2021/10/01--. Then on the 4th of November I got my first dosage of the vaccine.--2021/11/04-- I had heavy side effects.\nActivity Label: starting to experience symptoms" + }, + { + "role": "assistant", + "content": "20210701T0000" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing side effects of vaccination" + }, + { + "role": "assistant", + "content": "20211104T0000" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 3, "fields": { - "name": "END_DATE_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text, a given activity label and a given timestamp for the beginning of this activity and to then extract an end date to this activity label. Only output the extracted start date! Rely also on the context. Use averages if necessary. If there is no information about the end date at all, please state the start date also as the end date." - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: experiencing mild symptoms\nStart Date: 20200401T0000" - }, - { - "role": "assistant", - "content": "20200405T0000" - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: testing positive for Covid19\nStart Date: 20200405T0000" - }, - { - "role": "assistant", - "content": "20200405T0000" - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: getting infected again\nStart Date: 20200601T0000" - }, - { - "role": "assistant", - "content": "20200615T0000" - }, - { - "role": "user", - "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: having back pain\nStart Date: N/A" - }, - { - "role": "assistant", - "content": "N/A" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing side effects of \nStart Date: 20211104T0000" - }, - { - "role": "assistant", - "content": "20211106T0000" - }, - { - "role": "user", - "content": "Text: Four days after the first april 2020 I went to the doctor and got tested positive for Covid19. I was then hospitalized for two weeks.\nActivity Label: getting hospitalized\nStart Date: 20200405T0000" - }, - { - "role": "assistant", - "content": "20200419T0000" - }, - { - "role": "user", - "content": "Text: In the next time I made sure to improve my mental well being.\nActivity Label: improving mental well being\nStart Date: 20210610T0000" - }, - { - "role": "assistant", - "content": "20210710T0000" - } - ] + "name": "END_DATE_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text, a given activity label and a given timestamp for the beginning of this activity and to then extract an end date to this activity label. The text might contain dates in the format --YYYYMM/DD--, with two hyphens enclosing the date. Only use these as backup, in case no other time information is available. Only output the extracted end date! Rely on the context to determine the end date, as it might not be explicitly mentioned. Use averages if necessary. If there is no information about the end date at all, please state the start date also as the end date." + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever --2020/04/01--. Four days later I went to the doctor and got tested positive for Covid19--2020/04/01--. In June I got infected again--2020/04/01--. After that I had a back pain--2020/04/01--.\nActivity Label: experiencing mild symptoms\nStart Date: 20200401T0000" + }, + { + "role": "assistant", + "content": "20200405T0000" + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever --2020/04/01--. Four days later I went to the doctor and got tested positive for Covid19--2020/04/01--. In June I got infected again--2020/04/01--. After that I had a back pain--2020/04/01--..\nActivity Label: testing positive for Covid19\nStart Date: 20200405T0000" + }, + { + "role": "assistant", + "content": "20200405T0000" + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: getting infected again\nStart Date: 20200601T0000" + }, + { + "role": "assistant", + "content": "20200615T0000" + }, + { + "role": "user", + "content": "Text: On April 1, 2020, I started experiencing mild symptoms such as a persistent cough, fatigue, and a low-grade fever. Four days later I went to the doctor and got tested positive for Covid19. In June I got infected again. After that I had a back pain.\nActivity Label: having back pain\nStart Date: N/A" + }, + { + "role": "assistant", + "content": "N/A" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21--2021/07/21--. I then got tested positive for Covid19--2021/07/21--. In October I got infected again--2021/10/01--. Then on the 4th of November I got my first dosage of the vaccine--2021/11/04--. I had heavy side effects--2021/11/04--.\nActivity Label: experiencing side effects \nStart Date: 20211104T0000" + }, + { + "role": "assistant", + "content": "20211106T0000" + }, + { + "role": "user", + "content": "Text: Four days after the first of April 2020 I went to the doctor and got tested positive for Covid19. I was then hospitalized for two weeks.\nActivity Label: getting hospitalized\nStart Date: 20200405T0000" + }, + { + "role": "assistant", + "content": "20200419T0000" + }, + { + "role": "user", + "content": "Text: In the next time I made sure to improve my mental well being.\nActivity Label: improving mental well being\nStart Date: 20210610T0000" + }, + { + "role": "assistant", + "content": "20210710T0000" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 4, "fields": { - "name": "EVENT_TYPE_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text categorization and your job is to take a given activity label and to classify it into one of the following event types: 'Symptom Onset', 'Symptom Offset', 'Diagnosis', 'Doctor Visit', 'Treatment', 'Hospital Admission', 'Hospital Discharge', 'Medication', 'Lifestyle Change' and 'Feelings'. Please consider the capitalization." - }, - { - "role": "user", - "content": "visiting doctor's" - }, - { - "role": "assistant", - "content": "Doctors Visit" - }, - { - "role": "user", - "content": "testing positive for Covid19" - }, - { - "role": "assistant", - "content": "Diagnosis" - }, - { - "role": "user", - "content": "getting hospitalized" - }, - { - "role": "assistant", - "content": "Hospital Admission" - }, - { - "role": "user", - "content": "isolating at home" - }, - { - "role": "assistant", - "content": "Lifestyle Change" - }, - { - "role": "user", - "content": "prescribed medication for discomfort" - }, - { - "role": "assistant", - "content": "Medication" - }, - { - "role": "user", - "content": "seeking consultation with specialist" - }, - { - "role": "assistant", - "content": "Doctors Visit" - }, - { - "role": "user", - "content": "receiving vaccines to protect against Covid19" - }, - { - "role": "assistant", - "content": "Treatment" - }, - { - "role": "user", - "content": "feeling a sense of relief" - }, - { - "role": "assistant", - "content": "Feeling" - }, - { - "role": "user", - "content": "starting to experience symptoms" - }, - { - "role": "assistant", - "content": "Symptom Onset" - } - ] + "name": "EVENT_TYPE_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text categorization and your job is to take a given activity label and to classify it into one of the following event types: 'Symptom Onset', 'Symptom Offset', 'Diagnosis', 'Doctor Visit', 'Treatment', 'Hospital Admission', 'Hospital Discharge', 'Medication', 'Lifestyle Change' and 'Feelings'. Please consider the capitalization." + }, + { + "role": "user", + "content": "visiting doctor's" + }, + { + "role": "assistant", + "content": "Doctors Visit" + }, + { + "role": "user", + "content": "testing positive for Covid19" + }, + { + "role": "assistant", + "content": "Diagnosis" + }, + { + "role": "user", + "content": "getting hospitalized" + }, + { + "role": "assistant", + "content": "Hospital Admission" + }, + { + "role": "user", + "content": "isolating at home" + }, + { + "role": "assistant", + "content": "Lifestyle Change" + }, + { + "role": "user", + "content": "prescribed medication for discomfort" + }, + { + "role": "assistant", + "content": "Medication" + }, + { + "role": "user", + "content": "seeking consultation with specialist" + }, + { + "role": "assistant", + "content": "Doctors Visit" + }, + { + "role": "user", + "content": "receiving vaccines to protect against Covid19" + }, + { + "role": "assistant", + "content": "Treatment" + }, + { + "role": "user", + "content": "feeling a sense of relief" + }, + { + "role": "assistant", + "content": "Feeling" + }, + { + "role": "user", + "content": "starting to experience symptoms" + }, + { + "role": "assistant", + "content": "Symptom Onset" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 5, "fields": { - "name": "LOCATION_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text categorization and your job is to take a given activity label and categorize it into: 'Home', 'Hospital' or 'Doctors'. Use the context to categorize." - }, - { - "role": "user", - "content": "visiting doctor's" - }, - { - "role": "assistant", - "content": "Doctors" - }, - { - "role": "user", - "content": "consulting doctor over phone" - }, - { - "role": "assistant", - "content": "Home" - }, - { - "role": "user", - "content": "testing positive for Covid19" - }, - { - "role": "assistant", - "content": "Doctors" - }, - { - "role": "user", - "content": "getting hospitalized" - }, - { - "role": "assistant", - "content": "Hospital" - }, - { - "role": "user", - "content": "isolating at home" - }, - { - "role": "assistant", - "content": "Home" - }, - { - "role": "user", - "content": "prescribed medication for discomfort" - }, - { - "role": "assistant", - "content": "Doctors" - }, - { - "role": "user", - "content": "receiving special care with a ventilator" - }, - { - "role": "assistant", - "content": "Hospital" - }, - { - "role": "user", - "content": "receiving vaccines to protect against Covid19" - }, - { - "role": "assistant", - "content": "Doctors" - }, - { - "role": "user", - "content": "feeling a sense of relief" - }, - { - "role": "assistant", - "content": "Home" - }, - { - "role": "user", - "content": "starting to experience symptoms" - }, - { - "role": "assistant", - "content": "Home" - } - ] + "name": "LOCATION_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text categorization and your job is to take a given activity label and categorize it into: 'Home', 'Hospital' or 'Doctors'. Use the context to categorize." + }, + { + "role": "user", + "content": "visiting doctor's" + }, + { + "role": "assistant", + "content": "Doctors" + }, + { + "role": "user", + "content": "consulting doctor over phone" + }, + { + "role": "assistant", + "content": "Home" + }, + { + "role": "user", + "content": "testing positive for Covid19" + }, + { + "role": "assistant", + "content": "Doctors" + }, + { + "role": "user", + "content": "getting hospitalized" + }, + { + "role": "assistant", + "content": "Hospital" + }, + { + "role": "user", + "content": "isolating at home" + }, + { + "role": "assistant", + "content": "Home" + }, + { + "role": "user", + "content": "prescribed medication for discomfort" + }, + { + "role": "assistant", + "content": "Doctors" + }, + { + "role": "user", + "content": "receiving special care with a ventilator" + }, + { + "role": "assistant", + "content": "Hospital" + }, + { + "role": "user", + "content": "receiving vaccines to protect against Covid19" + }, + { + "role": "assistant", + "content": "Doctors" + }, + { + "role": "user", + "content": "feeling a sense of relief" + }, + { + "role": "assistant", + "content": "Home" + }, + { + "role": "user", + "content": "starting to experience symptoms" + }, + { + "role": "assistant", + "content": "Home" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 6, "fields": { - "name": "METRIC_ACTIVITY_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text categorization and your job is to take a given bulletpoint and to categorize it into 'No Relevance', 'Low Relevance', 'Moderate Relevance' or 'High Relevance'. It is really important, that that relevance category is correct. Category definition: No Relevance: Events or actions that are not connected to the progression or impact of the disease of the patient in any way. Low Relevance: Events or actions that have limited potential to affect the progression of the disease of the patient and hold minimal significance in its course. Moderate Relevance: Events or actions that possess some potential to influence the disease's progression of the patient but may not be critical to its outcome. High Relevance: Events or actions that hold substantial potential to impact the disease's course of the patient and are crucial in understanding its trajectory." - }, - { - "role": "user", - "content": "receiving support from my children" - }, - { - "role": "assistant", - "content": "Low Relevance" - }, - { - "role": "user", - "content": "taking medicine" - }, - { - "role": "assistant", - "content": "High Relevance" - }, - { - "role": "user", - "content": "eating chips" - }, - { - "role": "assistant", - "content": "No Relevance" - }, - { - "role": "user", - "content": "starting to experience symptoms" - }, - { - "role": "assistant", - "content": "High Relevance" - }, - { - "role": "user", - "content": "feeling side effects from vaccination" - }, - { - "role": "assistant", - "content": "Moderate Relevance" - } - ] + "name": "METRIC_ACTIVITY_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text categorization and your job is to take a given bulletpoint and to categorize it into 'No Relevance', 'Low Relevance', 'Moderate Relevance' or 'High Relevance'. It is really important, that that relevance category is correct. Category definition: No Relevance: Events or actions that are not connected to the progression or impact of the disease of the patient in any way. Low Relevance: Events or actions that have limited potential to affect the progression of the disease of the patient and hold minimal significance in its course. Moderate Relevance: Events or actions that possess some potential to influence the disease's progression of the patient but may not be critical to its outcome. High Relevance: Events or actions that hold substantial potential to impact the disease's course of the patient and are crucial in understanding its trajectory." + }, + { + "role": "user", + "content": "receiving support from my children" + }, + { + "role": "assistant", + "content": "Low Relevance" + }, + { + "role": "user", + "content": "taking medicine" + }, + { + "role": "assistant", + "content": "High Relevance" + }, + { + "role": "user", + "content": "eating chips" + }, + { + "role": "assistant", + "content": "No Relevance" + }, + { + "role": "user", + "content": "starting to experience symptoms" + }, + { + "role": "assistant", + "content": "High Relevance" + }, + { + "role": "user", + "content": "feeling side effects from vaccination" + }, + { + "role": "assistant", + "content": "Moderate Relevance" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 7, "fields": { - "name": "METRIC_TIMESTAMP_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text and to check if a given start date and end date of a given bulletpoint are correct. Correct is a start and end date in the format YYYYMMDDTHHMM if the date is appearing in the patient journey related to bulletpoint. If the start date and end date appearing in the context of the bulletpoint, you should output True. If there is another start or end date in the patient journey, the given timestamps are wrong and you should output False. If the start or end date is not appearing in the patient journey, it could be that the timestamp is estimated. In this case check if the estimation is reasonable and output True if it is and False if it is not." - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 20210721T0000\nEnd Date: 20210721T0000" - }, - { - "role": "assistant", - "content": "True" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 20210721T0000\nEnd Date: 20210724T0000" - }, - { - "role": "assistant", - "content": "True" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 07/21/2021\nEnd Date: 20210721T0000" - }, - { - "role": "assistant", - "content": "False" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 20210721T0000\nEnd Date: N/A" - }, - { - "role": "assistant", - "content": "False" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing heavy side effects of vaccination\nStart Date: 20211104T0000\nEnd Date: 20211107T0000" - }, - { - "role": "assistant", - "content": "True" - }, - { - "role": "user", - "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing heavy side effects of vaccination\nStart Date: 20211201T0000\nEnd Date: 20211204T0000" - }, - { - "role": "assistant", - "content": "False" - } - ] + "name": "METRIC_TIMESTAMP_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text and to check if a given start date and end date of a given bulletpoint are correct. Correct is a start and end date in the format YYYYMMDDTHHMM if the date is appearing in the patient journey related to bulletpoint. If the start date and end date appearing in the context of the bulletpoint, you should output True. If there is another start or end date in the patient journey, the given timestamps are wrong and you should output False. If the start or end date is not appearing in the patient journey, it could be that the timestamp is estimated. In this case check if the estimation is reasonable and output True if it is and False if it is not." + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 20210721T0000\nEnd Date: 20210721T0000" + }, + { + "role": "assistant", + "content": "True" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 20210721T0000\nEnd Date: 20210724T0000" + }, + { + "role": "assistant", + "content": "True" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 07/21/2021\nEnd Date: 20210721T0000" + }, + { + "role": "assistant", + "content": "False" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: starting to experience symptoms\nStart Date: 20210721T0000\nEnd Date: N/A" + }, + { + "role": "assistant", + "content": "False" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing heavy side effects of vaccination\nStart Date: 20211104T0000\nEnd Date: 20211107T0000" + }, + { + "role": "assistant", + "content": "True" + }, + { + "role": "user", + "content": "Text: I started experiencing flu-like symptoms in July 21. I then got tested positive for Covid19. In October I got infected again. Then on the 4th of November I got my first dosage of the vaccine. I had heavy side effects.\nActivity Label: experiencing heavy side effects of vaccination\nStart Date: 20211201T0000\nEnd Date: 20211204T0000" + }, + { + "role": "assistant", + "content": "False" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 8, "fields": { - "name": "COMPARE_MESSAGES", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": " You are an expert in text understanding and your job is to understand the semantical meaning of bulletpoints and compare the semantic to each other. So you take two bulletpoints and check if they are semantically similar. You should return True if you think they are similar and False if you don't." - }, - { - "role": "user", - "content": "First: receiving support from my children\nSecond: taking medicine" - }, - { - "role": "assistant", - "content": "False" - }, - { - "role": "user", - "content": "First: visiting doctor's\nSecond: going to the doctor" - }, - { - "role": "assistant", - "content": "True" - }, - { - "role": "user", - "content": "First: experiencing covid 19 symptoms\nSecond: first symptoms of covid 19" - }, - { - "role": "assistant", - "content": "True" - }, - { - "role": "user", - "content": "First: experiencing first covid 19 symptoms\nSecond: experiencing worse symptoms" - }, - { - "role": "assistant", - "content": "False" - } - ] + "name": "COMPARE_MESSAGES", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": " You are an expert in text understanding and your job is to understand the semantical meaning of bulletpoints and compare the semantic to each other. So you take two bulletpoints and check if they are semantically similar. You should return True if you think they are similar and False if you don't." + }, + { + "role": "user", + "content": "First: receiving support from my children\nSecond: taking medicine" + }, + { + "role": "assistant", + "content": "False" + }, + { + "role": "user", + "content": "First: visiting doctor's\nSecond: going to the doctor" + }, + { + "role": "assistant", + "content": "True" + }, + { + "role": "user", + "content": "First: experiencing covid 19 symptoms\nSecond: first symptoms of covid 19" + }, + { + "role": "assistant", + "content": "True" + }, + { + "role": "user", + "content": "First: experiencing first covid 19 symptoms\nSecond: experiencing worse symptoms" + }, + { + "role": "assistant", + "content": "False" + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 9, "fields": { - "name": "COHORT_TAG_MESSAGES", - "category": "few-shot", - "text": [ - [ - "condition", - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the illness it is about." - }, - { - "role": "user", - "content": "In July I got infected with Covid-19 which resulted in similar symptoms like a heavy flu." - }, - { - "role": "assistant", - "content": "Covid-19" - }, - { - "role": "user", - "content": "I had a heavy flu in July." - }, - { - "role": "assistant", - "content": "Flu" - }, - { - "role": "user", - "content": "Last year I was feeling really well, when all of a sudden I had severe breathtaking problems and high fever. I thought it was a flu, but it turned out to be Covid-19." - }, - { - "role": "assistant", - "content": "Covid-19" - } - ], - [ - "sex", - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the gender of the author. If the gender isn't clear, you should take the context into account. Only if the context doesn't help, you should return 'N/A'." - }, - { - "role": "user", - "content": "I am a 25 year old software engineer living in California with my girlfriend. When I got Covid-19 last year I was really worried about my job and my girlfriend." - }, - { - "role": "assistant", - "content": "male" - }, - { - "role": "user", - "content": "I am a nurse living in Berlin with my boyfriend. When I got Covid-19 last year I was really worried about my job and my boyfriend." - }, - { - "role": "assistant", - "content": "female" - }, - { - "role": "user", - "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" - }, - { - "role": "assistant", - "content": "N/A" - }, - { - "role": "user", - "content": "I am a 25 year old software engineer living in California with my girlfriend. When I got Covid-19 that struck me as a mother of two really heavily." - }, - { - "role": "assistant", - "content": "female" - }, - { - "role": "user", - "content": "I am a nurse living in Berlin. When I got Covid-19 I had to stay home what really hit me. As a divorced father I only see my boy once every month and now I couldn't even do that." - }, - { - "role": "assistant", - "content": "male" - } - ], - [ - "age", - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the age of the author. If the gender isn't clear, you should take the context into account. Young means 25, middle aged 50 and old 75. Only if the context doesn't help, you should return 'N/A'." - }, - { - "role": "user", - "content": "I am a 22 year old software engineer living in California with my girlfriend. When I got Covid-19 last year I was really worried about my job and my girlfriend." - }, - { - "role": "assistant", - "content": "22" - }, - { - "role": "user", - "content": "I am a nurse living in Berlin. When I got Covid-19 I had to stay home what really hit me. Luckily as a young person I recovered quickly." - }, - { - "role": "assistant", - "content": "25" - }, - { - "role": "user", - "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" - }, - { - "role": "assistant", - "content": "N/A" - }, - { - "role": "user", - "content": "I am an old man, so Covid-19 wasn't all easy on me." - }, - { - "role": "assistant", - "content": "75" - } - ], - [ - "origin", - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the origin country of the author. If the origin isn't clear, you should take the context into account. Only if the context doesn't help, you should return 'N/A'." - }, - { - "role": "user", - "content": "I am a 25 year old software engineer living in California with my girlfriend. When I got Covid-19 last year I was really worried about my job and my girlfriend." - }, - { - "role": "assistant", - "content": "United States of America" - }, - { - "role": "user", - "content": "I am a nurse living in Berlin. When I got Covid-19 I had to stay home what really hit me. Luckily as a young person I recovered quickly." - }, - { - "role": "assistant", - "content": "Germany" - }, - { - "role": "user", - "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" - }, - { - "role": "assistant", - "content": "N/A" - } - ], - [ - "preexisting_condition", - { - "role": "system", - "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract previous diseases of the author. These diseases have to be EXPLICITLY MENTIONED. And they have to have occured BEFORE the illness the text is about!" - }, - { - "role": "user", - "content": "I got Covid-19 last year, which was hard since I since ever had to fight Asthma." - }, - { - "role": "assistant", - "content": "Asthma" - }, - { - "role": "user", - "content": "I infected me with Covid-19 right after I recovered from a heavy cold." - }, - { - "role": "assistant", - "content": "Cold" - }, - { - "role": "user", - "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" - }, - { - "role": "assistant", - "content": "N/A" - }, - { - "role": "user", - "content": "I got Covid-19 last year after I already got it right at the start in 2020." - }, - { - "role": "assistant", - "content": "Covid-19" - } + "name": "COHORT_TAG_MESSAGES", + "category": "few-shot", + "text": [ + [ + "condition", + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the illness it is about. Return only the condition using two words a most." + }, + { + "role": "user", + "content": "In July I got infected with Covid-19 which resulted in similar symptoms like a heavy flu." + }, + { + "role": "assistant", + "content": "Covid-19" + }, + { + "role": "user", + "content": "I had a heavy flu in July." + }, + { + "role": "assistant", + "content": "Flu" + }, + { + "role": "user", + "content": "Last year I was feeling really well, when all of a sudden I had severe breathtaking problems and high fever. I thought it was a flu, but it turned out to be Covid-19." + }, + { + "role": "assistant", + "content": "Covid-19" + } + ], + [ + "gender", + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the gender of the author. If the gender isn't clear, you should take the context into account. Only if the context doesn't help, you should return 'N/A'." + }, + { + "role": "user", + "content": "I am a 25 year old software engineer living in California with my girlfriend. When I got Covid-19 last year I was really worried about my job and my girlfriend." + }, + { + "role": "assistant", + "content": "male" + }, + { + "role": "user", + "content": "I am a nurse living in Berlin with my boyfriend. When I got Covid-19 last year I was really worried about my job and my boyfriend." + }, + { + "role": "assistant", + "content": "female" + }, + { + "role": "user", + "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" + }, + { + "role": "assistant", + "content": "N/A" + }, + { + "role": "user", + "content": "I am a 25 year old software engineer living in California with my girlfriend. When I got Covid-19 that struck me as a mother of two really heavily." + }, + { + "role": "assistant", + "content": "female" + }, + { + "role": "user", + "content": "I am a nurse living in Berlin. When I got Covid-19 I had to stay home what really hit me. As a divorced father I only see my boy once every month and now I couldn't even do that." + }, + { + "role": "assistant", + "content": "male" + } + ], + [ + "age", + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the age of the author. If the gender isn't clear, you should take the context into account. Young means 25, middle aged 50 and old 75. Only if the context doesn't help, you should return 'N/A'." + }, + { + "role": "user", + "content": "I am a 22 year old software engineer living in California with my girlfriend. When I got Covid-19 last year I was really worried about my job and my girlfriend." + }, + { + "role": "assistant", + "content": "22" + }, + { + "role": "user", + "content": "I am a nurse living in Berlin. When I got Covid-19 I had to stay home what really hit me. Luckily as a young person I recovered quickly." + }, + { + "role": "assistant", + "content": "25" + }, + { + "role": "user", + "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" + }, + { + "role": "assistant", + "content": "N/A" + }, + { + "role": "user", + "content": "I am an old man, so Covid-19 wasn't all easy on me." + }, + { + "role": "assistant", + "content": "75" + } + ], + [ + "origin", + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract the origin country of the author. If the origin isn't clear, you should take the context into account. Only if the context doesn't help, you should return 'N/A'. Return only the country of origin using two words a most." + }, + { + "role": "user", + "content": "I am a 25 year old software engineer living in California with my girlfriend. When I got Covid-19 last year I was really worried about my job and my girlfriend." + }, + { + "role": "assistant", + "content": "United States of America" + }, + { + "role": "user", + "content": "I am a nurse living in Berlin. When I got Covid-19 I had to stay home what really hit me. Luckily as a young person I recovered quickly." + }, + { + "role": "assistant", + "content": "Germany" + }, + { + "role": "user", + "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" + }, + { + "role": "assistant", + "content": "N/A" + } + ], + [ + "preexisting_condition", + { + "role": "system", + "content": "You are an expert in text understanding and your job is to take a given text about an illness and to extract previous diseases of the author. These diseases have to be EXPLICITLY MENTIONED. And they have to have occured BEFORE the illness the text is about! Return only the preexisting disease using two words a most." + }, + { + "role": "user", + "content": "I got Covid-19 last year, which was hard since I since ever had to fight Asthma." + }, + { + "role": "assistant", + "content": "Asthma" + }, + { + "role": "user", + "content": "I infected me with Covid-19 right after I recovered from a heavy cold." + }, + { + "role": "assistant", + "content": "Cold" + }, + { + "role": "user", + "content": "I got Covid-19 last year and I was really worried about my job. The diesease itself wasn't even that hard but it stressed me out, that I wasn't allowed to go to my job!" + }, + { + "role": "assistant", + "content": "N/A" + }, + { + "role": "user", + "content": "I got Covid-19 last year after I already got it right at the start in 2020." + }, + { + "role": "assistant", + "content": "Covid-19" + } + ] ] - ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 10, "fields": { - "name": "PREPROCESSING_SPELLCHECK", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text analysis with a focus on spelling accuracy. Your task is to identify any spelling errors in the provided text and correct them. Ensure the corrected text is accurate and readable. Please make sure to give out the full text without shorten it." - }, - { - "role": "user", - "content": "I remeber the day I first learnt about the importnce of spellchek. It was an eye-opener for me." - }, - { - "role": "assistant", - "content": "I remember the day I first learned about the importance of spellcheck. It was an eye-opener for me." - } - ] + "name": "PREPROCESSING_SPELLCHECK", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis with a focus on spelling accuracy. Your task is to identify any spelling errors in the provided text and correct them. Ensure the corrected text is accurate and readable. Please make sure to give out the full text without shortening it." + }, + { + "role": "user", + "content": "I remeber the day I first learnt about the importnce of spellchek. It was an eye-opener for me." + }, + { + "role": "assistant", + "content": "I remember the day I first learned about the importance of spellcheck. It was an eye-opener for me." + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 11, "fields": { - "name": "PREPROCESSING_PUNCTUATION", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text analysis with a focus on grammatical accuracy, specifically punctuation and comma usage. Your task is to identify any punctuation or comma errors in the provided text and correct them. Ensure the corrected text is accurate, readable, and follows standard punctuation rules. Please make sure to give out the full text without shortening it." - }, - { - "role": "user", - "content": "Despite the rainy weather many people attended the outdoor concert, which, was surprising. The band played hit after hit, and the crowd's enthusiasm, was infectious even the most reserved attendees found themselves dancing." - }, - { - "role": "assistant", - "content": "Despite the rainy weather, many people attended the outdoor concert, which was surprising. The band played hit after hit, and the crowd's enthusiasm was infectious; even the most reserved attendees found themselves dancing." - } - ] + "name": "PREPROCESSING_PUNCTUATION", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis with a focus on grammatical accuracy, specifically punctuation and comma usage. Your task is to identify any punctuation or comma errors in the provided text and correct them. Ensure the corrected text is accurate, readable, and follows standard punctuation rules. Please make sure to give out the full text without shortening it." + }, + { + "role": "user", + "content": "Despite the rainy weather many people attended the outdoor concert, which, was surprising. The band played hit after hit, and the crowd's enthusiasm, was infectious even the most reserved attendees found themselves dancing." + }, + { + "role": "assistant", + "content": "Despite the rainy weather, many people attended the outdoor concert, which was surprising. The band played hit after hit, and the crowd's enthusiasm was infectious; even the most reserved attendees found themselves dancing." + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 12, "fields": { - "name": "PREPROCESSING_IDENTIFY_TIMESTAMPS", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text analysis. Your task is to identify and extract any timestamps (specific dates, months, years, recognized holidays, timeframes like '12 weeks later', or periods between specific dates) mentioned in the context of an individual experiencing symptoms or being diagnosed with an illness. Highlight these timestamps within the text by surrounding them with $$$ symbols. Ensure the full text is presented without any omissions, and only the timestamps are highlighted in this manner." - }, - { - "role": "user", - "content": "I started feeling unwell around the middle of March 2021. The symptoms were quite severe by the 20th of March, which is when I decided to get tested. The test results came back positive for Covid-19 on March 22nd, 2021." - }, - { - "role": "assistant", - "content": "I started feeling unwell around the middle of $$$March 2021$$$. The symptoms were quite severe by the $$$20th of March$$$, which is when I decided to get tested. The test results came back positive for Covid-19 on $$$March 22nd, 2021$$$." - }, - { - "role": "user", - "content": "I started feeling unusually fatigued right before Thanksgiving 2020. The fatigue worsened over the holiday, and by the following Monday, I had developed a fever. I was tested for Covid-19 two days later and received a positive result on November 30th, 2020." - }, - { - "role": "assistant", - "content": "I started feeling unusually fatigued right before $$$Thanksgiving 2020$$$. The fatigue worsened over the holiday, and by the following Monday, I had developed a fever. I was tested for Covid-19 $$$two days later$$$ and received a positive result on $$$November 30th, 2020$$$." - } - ] + "name": "PREPROCESSING_TIME_IDENTIFICATION", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis. Your task is to identify timestamps of events in the given text. Those can be: specific dates, months, years, recognized holidays, relative dates like '12 weeks later' or 'as the week progressed'. Highlight these timestamps within the text by surrounding them with $$$ symbols. Return the full text with the highlighted time specifications." + }, + { + "role": "user", + "content": "I started feeling unwell around the middle of March 2021. The symptoms were quite severe by the 20th of March, which is when I decided to get tested. The test results came back positive for Covid-19 on March 22nd, 2021." + }, + { + "role": "assistant", + "content": "I started feeling unwell around the $$$middle of March 2021$$$. The symptoms were quite severe by the $$$20th of March$$$, which is when I decided to get tested. The test results came back positive for Covid-19 on $$$March 22nd, 2021$$$." + }, + { + "role": "user", + "content": "I started feeling unusually fatigued right before Thanksgiving 2020. The fatigue worsened over the holiday, and by the following Monday, I had developed a fever. I was tested for Covid-19 two days later and received a positive result on November 30th, 2020." + }, + { + "role": "assistant", + "content": "I started feeling unusually fatigued right before $$$Thanksgiving 2020$$$. The fatigue worsened over the holiday, and by the $$$following Monday$$$, I had developed a fever. I was tested for Covid-19 $$$two days later$$$ and received a positive result on $$$November 30th, 2020$$$." + }, + { + "role": "user", + "content": "Two days after new years eve, I started feeling sick. In the following week my symptoms worsened." + }, + { + "role": "assistant", + "content": "$$$Two days after$$$ $$$new years eve$$$, I started feeling sick. $$$In the following week$$$ my symptoms worsened." + }, + { + "role": "user", + "content": "I was tested positive for Covid-19 on by birthday, the 12th of June. The day before I already felt light-headed. Two weeks after my birthday, I was admitted to the hospital." + }, + { + "role": "assistant", + "content": "I was tested positive for Covid-19 on by birthday, $$$the 12th of June$$$. $$$The day before$$$ I already felt light-headed. $$$Two weeks after my birthday$$$, I was admitted to the hospital." + }, + { + "role": "user", + "content": "Over the course of the next few days, my symptoms progressed, and I started experiencing high fever. After two weeks of isolation, I finally started feeling better." + }, + { + "role": "assistant", + "content": "$$$Over the course of the next few days$$$, my symptoms progressed, and I started experiencing high fever. $$$After two weeks$$$ of isolation, I finally started feeling better." + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 13, "fields": { - "name": "PREPROCESSING_TRANSFORM_TIMESTAMPS", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text analysis and date formatting. Your task is to identify any timestamps related to when an individual experienced symptoms or was diagnosed with an illness. Convert and present these timestamps in the specific format of YYYY/MM/DD. All relevant time specifications are already highlighted with $$$ $$$. To guarantee the completeness of the date you must make assumptions about the year, month and day based on the context. If the time specification is a duration, based on context, you must make assumptions about the start date of the duration. If there is no information about the year, month or day, you are allowed to assume the current year, month or day. Ensure the full text is presented without any omissions, and try to transform every timestamps as concrete as possible. Please make sure to give out the full text without shortening it." - }, - { - "role": "user", - "content": "I noticed the first symptoms shortly after my birthday in $$$April$$$, and exactly $$$12 weeks later$$$, my condition had deteriorated significantly. I was officially diagnosed with Lyme disease on $$$August 7th$$$. In $$$early 2025$$$, it will be gone!" - }, - { - "role": "assistant", - "content": "I noticed the first symptoms shortly after my birthday on 2024/04/01, and exactly 12 weeks later, on 2024/06/24, my condition had deteriorated significantly. I was officially diagnosed with Lyme disease on 2024/08/07. It will be gone on 2025/01/01!" - }, - { - "role": "user", - "content": "During the period between $$$the 01.02 and the 03.02$$$, I felt unusually tired, but I thought it was just stress. However, after attending a large event $$$two weeks later$$$, I developed a fever and was tested positive for the flu." - }, - { - "role": "assistant", - "content": "During the period between 2024/02/01 and 2024/02/03, I felt unusually tired, but I thought it was just stress. However, after attending a large event two weeks later, on 2024/02/17, I developed a fever and was tested positive for the flu." - } - ] + "name": "PREPROCESSING_TRANSFORM_TIMESTAMPS", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis and date formatting. Convert these timestamps in the specific format of YYYY/MM/DD. Some relevant time specifications are highlighted with $$$ symbols in the text, focus on those. To guarantee the completeness of the date you must make assumptions about the year, month and day based on the context. If the time specification is a duration, based on context, you must make assumptions about the start date of the duration. If there is no information about the year, month or day, you are allowed to assume the current year, month or day. Ensure the full text is presented without any omissions and transform every timestamps as concrete as possible. Please make sure to give out the full text without shortening it." + }, + { + "role": "user", + "content": "I noticed the first symptoms shortly after my birthday in $$$April$$$, and exactly $$$12 weeks later$$$, my condition had deteriorated significantly. I was officially diagnosed with Lyme disease on $$$August 7th$$$. In $$$early 2025$$$, it will be gone!" + }, + { + "role": "assistant", + "content": "I noticed the first symptoms shortly after my birthday on 2024/04/01, and exactly 12 weeks later, on 2024/06/24, my condition had deteriorated significantly. I was officially diagnosed with Lyme disease on 2024/08/07. It will be gone on 2025/01/01!" + }, + { + "role": "user", + "content": "During the period between $$$the 01.02 and the 03.02$$$, I felt unusually tired, but I thought it was just stress. However, after attending a large event $$$two weeks later$$$, I developed a fever and was tested positive for the flu." + }, + { + "role": "assistant", + "content": "During the period between 2024/02/01 and 2024/02/03, I felt unusually tired, but I thought it was just stress. However, after attending a large event two weeks later, on 2024/02/17, I developed a fever and was tested positive for the flu." + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 14, "fields": { - "name": "PREPROCESSING_TIME_CALCULATION", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text analysis and date calculations. Your task is to identify timestamps related to health events or diagnoses and convert these into concrete dates in the format of YYYY/MM/DD. For relative timestamps (like 'a few weeks after' or 'months before'), calculate the exact dates based on provided or assumed known dates. Ensure the text is complete without omission, with all relevant timestamps accurately transformed to the specified format. Please make sure to give out the full text without shortening it." - }, - { - "role": "user", - "content": "After experiencing severe headaches starting in mid-$$$March 2022$$$, I went to see a neurologist. The MRI scan scheduled $$$three weeks later$$$ confirmed that I had a benign brain tumor. Post-surgery, I began my recovery phase, which lasted until $$$four months later$$$. During a follow-up visit $$$two months after my recovery$$$, my doctor confirmed that my condition had improved significantly." - }, - { - "role": "assistant", - "content": "After experiencing severe headaches starting on 2022/03/15, I went to see a neurologist. The MRI scan scheduled on 2022/04/05 confirmed that I had a benign brain tumor. Post-surgery, I began my recovery phase, which lasted until 2022/08/05. During a follow-up visit on 2022/10/05, my doctor confirmed that my condition had improved significantly." - }, - { - "role": "user", - "content": "Early July 2020, I started experiencing severe coughing and a high fever. It turned out I had contracted Covid-19. And in $$$early August$$$ I had lost my sense of taste." - }, - { - "role": "assistant", - "content": "On the 2020/06/01, I started experiencing severe coughing and a high fever. It turned out I had contracted Covid-19. And on 2020/08/01 I had lost my sense of taste." - } - ] + "name": "PREPROCESSING_TIME_RELATIVE", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis and temporal relations. Your task is to convert relative time information (like 'a few weeks after' or 'in the following days') into concrete dates in the format of YYYY/MM/DD. For relative timestamps like 'two days after my birthday' or 'the day before that', calculate the exact dates based on other dates in the text. If this information is missing, make reasonable assumptions. Some relevant time specifications are highlighted with $$$ symbols in the text, focus on those. Return the full text with the transformed timestamps." + }, + { + "role": "user", + "content": "After experiencing severe headaches starting on 2022/03/15$, I went to see a neurologist. The MRI scan scheduled $$$three weeks later$$$ confirmed that I had a benign brain tumor. Post-surgery, I began my recovery phase, which lasted until $$$four months later$$$. During a follow-up visit $$$two weeks after my recovery$$$, my doctor confirmed that my condition had improved significantly." + }, + { + "role": "assistant", + "content": "After experiencing severe headaches starting on 2022/03/15, I went to see a neurologist. The MRI scan scheduled on 2022/04/05 confirmed that I had a benign brain tumor. Post-surgery, I began my recovery phase, which lasted until 2022/08/05. During a follow-up visit on 2022/08/19, my doctor confirmed that my condition had improved significantly." + }, + { + "role": "user", + "content": "On the 2020/01/06, I started experiencing severe coughing and a high fever. It turned out I had contracted Covid-19. And in $$$the following weeks$$$ I had lost my sense of taste." + }, + { + "role": "assistant", + "content": "On the 2020/06/01, I started experiencing severe coughing and a high fever. It turned out I had contracted Covid-19. And during 2020/06/01 and 2020/06/15 I lost my sense of taste." + }, + { + "role": "user", + "content": "I was diagnosed with diabetes on 2023/05/01. $$$A few days later$$$, I began experiencing extreme fatigue and dizziness." + }, + { + "role": "assistant", + "content": "I was diagnosed with diabetes on 2023/05/01. On 2023/05/04, I began experiencing extreme fatigue and dizziness." + }, + { + "role": "user", + "content": "I started chemotherapy on 2022/09/15. $$$Two weeks after the treatment$$$, my hair started falling out." + }, + { + "role": "assistant", + "content": "I started chemotherapy on 2022/09/15. On 2022/09/29, my hair started falling out." + }, + { + "role": "user", + "content": "I had surgery to remove a tumor on 2023/03/10. $$$In the following week$$$, I developed an infection at the surgical site." + }, + { + "role": "assistant", + "content": "I had surgery to remove a tumor on 2023/03/10. Between 2023/03/10 and 2023/0317, I developed an infection at the surgical site." + }, + { + "role": "user", + "content": "I began taking new medication for my condition on 2022/07/01. $$$A month after starting the medication$$$, I noticed significant improvements in my symptoms." + }, + { + "role": "assistant", + "content": "I began taking new medication for my condition on 2022/07/01. On 2022/08/01, I noticed significant improvements in my symptoms." + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 15, "fields": { - "name": "PREPROCESSING_TIME_INTERPRETATION", - "category": "few-shot", - "text": [ - { - "role": "system", - "content": "You are an expert in text analysis with a specialization in date formatting and interpretation. Your task is to transform general time references related to health events or any other context into specific dates in the format of YYYY/MM/DD. Specifically, convert 'early [month]' to the 1st of the month, 'mid [month]' to the 15th of the month, and 'end of [month]' to the last day of the month (use 30 for April, June, September, and November; 31 for January, March, May, July, August, October, and December; and 28 or 29 for February, depending on leap years). If the year is not mentioned, assume the current year. Provide the full text without omission, ensuring all general time references are accurately transformed into the specified format. Example transformations: 'early January 2020' becomes 2020/01/01, 'mid January 2020' becomes 2020/01/15, and 'end of January 2020' becomes 2020/01/31." - }, - { - "role": "user", - "content": "In early January, I noticed a persistent cough. By mid January, the cough had worsened, leading me to seek medical advice. A specialist finally saw me at the end of January, diagnosing me with a chronic condition." - }, - { - "role": "assistant", - "content": "In 2020/01/01, I noticed a persistent cough. By 2020/01/15, the cough had worsened, leading me to seek medical advice. A specialist finally saw me at 2020/01/31, diagnosing me with a chronic condition." - }, - { - "role": "user", - "content": "In the middle of 2023 I got a stroke. By the end of the year I had recovered. But in early 2024 I had a relapse." - }, - { - "role": "assistant", - "content": "On 2023/06/01, I got a stroke. By 2023/12/01, I had recovered, On 2024/01/01, I had a relapse." - } - ] + "name": "PREPROCESSING_TIME_GENERAL", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis and date formatting. Your task is to transform unspecific time references into specific dates in the format of YYYY/MM/DD. Some relevant time specifications are highlighted with $$$ symbols in the text, focus on those. Specifically, convert 'early [month]' to the 1st of the month, 'mid [month]' to the 15th of the month, and 'end of [month]' to the last day of the month (use 30 for April, June, September, and November; 31 for January, March, May, July, August, October, and December; and 28 or 29 for February, depending on leap years). If the year is not mentioned, assume the current year. Return the full text, with the transformed timestamps." + }, + { + "role": "user", + "content": "$$$In early January$$$, I noticed a persistent cough. By $$$mid January$$$, the cough had worsened, leading me to seek medical advice. A specialist finally saw me $$$at the end of January$$$, diagnosing me with a chronic condition." + }, + { + "role": "assistant", + "content": "In 2020/01/01, I noticed a persistent cough. By 2020/01/15, the cough had worsened, leading me to seek medical advice. A specialist finally saw me at 2020/01/31, diagnosing me with a chronic condition." + }, + { + "role": "user", + "content": "In the $$$middle of 2023$$$ I got a stroke. By the $$$end of the year$$$ I had recovered. But in $$$early 2024$$$ I had a relapse." + }, + { + "role": "assistant", + "content": "On 2023/06/01, I got a stroke. By 2023/12/01, I had recovered. On 2024/01/01, I had a relapse." + }, + { + "role": "user", + "content": "I plan to start my new fitness routine in $$$early February 2024$$$. By $$$mid February$$$, I hope to see some initial results. By the $$$end of February$$$, I want to have a consistent habit." + }, + { + "role": "assistant", + "content": "I plan to start my new fitness routine on 2024/02/01. By 2024/02/15, I hope to see some initial results. By 2024/02/29, I want to have a consistent habit." + }, + { + "role": "user", + "content": "I usually experience seasonal allergies in $$$early April$$$. By $$$mid April$$$, they become severe, and by the $$$end of May$$$, I need to take stronger medication." + }, + { + "role": "assistant", + "content": "I usually experience seasonal allergies on 2024/04/01. By 2024/04/15, they become severe, and by 2024/05/31, I need to take stronger medication." + }, + { + "role": "user", + "content": "I started feeling unwell around the $$$middle of March 2021$$$. The symptoms were quite severe by the $$$20th of March$$$, which is when I decided to get tested. The test results came back positive for Covid-19 on $$$March 22nd, 2021$$$." + }, + { + "role": "assistant", + "content": "I started feeling unwell around the 2021/03/15. The symptoms were quite severe by the 2021/03/20, which is when I decided to get tested. The test results came back positive for Covid-19 on 2021/03/22." + } + ] } - }, - { +}, +{ "model": "extraction.prompt", "pk": 16, "fields": { - "name": "CREATE_PATIENT_JOURNEY", - "category": "zero-shot", - "text": [ - { - "role": "user", - "content": "Please outline the course of your Covid-19 infection, what you did (and when you did that) because of it and which doctors you may consulted. Please give some information about the time, in a few cases directly as a date and in the other as something in the lines of 'in the next days', 'the week after that' or similar. Give your outline as a continuous text. Also include if you later went for getting a vaccine and if so, how often. You don't have to include deals about who you are. Please include 100 to 400 words, but not more than 400." - } - ] + "name": "CREATE_PATIENT_JOURNEY", + "category": "zero-shot", + "text": [ + { + "role": "user", + "content": "Please outline the course of your Covid-19 infection, what you did (and when you did that) because of it and which doctors you may consulted. Please give some information about the time, in a few cases directly as a date and in the other as something in the lines of 'in the next days', 'the week after that' or similar. Give your outline as a continuous text. Also include if you later went for getting a vaccine and if so, how often. You don't have to include deals about who you are. Please include 100 to 400 words, but not more than 400." + } + ] + } +}, +{ + "model": "extraction.prompt", + "pk": 17, + "fields": { + "name": "PREPROCESSING_TIME_HOLIDAYS", + "category": "few shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text analysis and date formatting. Your task is to identify time information that is related to holidays and to convert them into concrete timestamps. Some relevant time specifications are highlighted with $$$ symbols in the text, focus on those. There are also time specifications highlighted, that are not holidays, ignore them. If no information about the year is given, assume the current year. Use the format YYYY/MM/DD. Only transform the time information that is related to holidays. Keep all other time information highlighted." + }, + { + "role": "user", + "content": "$$$Two days after$$$ $$$new years eve$$$, I started feeling sick." + }, + { + "role": "assistant", + "content": "$$$Two days after$$$ 2023/12/31, I started feeling sick." + }, + { + "role": "user", + "content": "I started feeling unusually fatigued right before $$$Thanksgiving 2020$$$." + }, + { + "role": "assistant", + "content": "I started feeling unusually fatigued right before 2020/11/26." + }, + { + "role": "assistant", + "content": "I always feel excited on 2023/10/31 and then exhausted the next day." + }, + { + "role": "user", + "content": "I visited my grandparents $$$two weeks before$$$ $$$Christmas$$$ last year." + }, + { + "role": "assistant", + "content": "I visited my grandparents $$$two weeks before$$$ 2022/12/25 last year." + }, + { + "role": "user", + "content": "We planned a big family reunion for $$$Easter$$$, but it got postponed." + }, + { + "role": "assistant", + "content": "We planned a big family reunion for 2023/04/09, but it got postponed." + }, + { + "role": "user", + "content": "My annual check-up is always scheduled for $$$mid June$$$, just after $$$Flag Day$$$." + }, + { + "role": "assistant", + "content": "My annual check-up is always scheduled for $$$mid June$$$, just after 2023/06/14." + } + ] + } +}, +{ + "model": "extraction.prompt", + "pk": 18, + "fields": { + "name": "PREPROCESSING_TIME_PROPAGATE", + "category": "few-shot", + "text": [ + { + "role": "system", + "content": "You are an expert in text understanding and information extraction. Your task is to propagate temporal information throughout a given text. For each sentence, append the latest known timestamp in the format --YYYY/MM/DD-- before the period. Instructions:1. Identify the most recent date mentioned up to and including the current sentence. This includes relative dates like 'after two weeks' or 'in the following das'. Translate these specifications into concrete dates, if you encounter them. 2. Only if no new temporal information is given, reuse the added timestamp from the previous sentence. 3.Append this date at the end of the current sentence before the period." + }, + { + "role": "user", + "content": "0: After experiencing the first symptoms of Covid-19 on 2020/09/13, I isolated myself at home.\n1: My symptoms started with a mild fever and worsened over the following days.\n2: By 2020/09/15, I developed difficulty breathing and consulted a doctor via telemedicine.\n3: The doctor advised me to monitor my symptoms closely and prescribed medications." + }, + { + "role": "assistant", + "content": "0: After experiencing the first symptoms of Covid-19 on 2020/09/13, I isolated myself at home--2020/09/13--.1: My symptoms started with a mild fever and worsened over the following days--2020/09/13--.2: By 2020/09/15, I developed difficulty breathing and consulted a doctor via telemedicine--2020/09/15--.3: The doctor advised me to monitor my symptoms closely and prescribed medications--2020/09/15--." + }, + { + "role": "user", + "content": "15: After a week in the hospital, my breathing got better, and they let me go home on 2022/01/25. 16: I was super happy to be back in my own bed, but I still felt exhausted." + }, + { + "role": "assistant", + "content": "15: After a week in the hospital, my breathing got better, and they let me go home on 2022/01/25--2022/01/25--.16: I was super happy to be back in my own bed, but I still felt exhausted--2022/01/25--." + } + ] } - } +} ] diff --git a/tracex_project/extraction/logic/modules/module_activity_labeler.py b/tracex_project/extraction/logic/modules/module_activity_labeler.py index e56789bf..ecb3228f 100644 --- a/tracex_project/extraction/logic/modules/module_activity_labeler.py +++ b/tracex_project/extraction/logic/modules/module_activity_labeler.py @@ -46,7 +46,7 @@ def execute( patient_journey_sentences ) activity_labels: pd.DataFrame = self.__extract_activities( - patient_journey_numbered, condition + patient_journey_numbered, condition, len(patient_journey_sentences) ) return activity_labels @@ -68,7 +68,7 @@ def __number_patient_journey_sentences(patient_journey_sentences: List[str]) -> @staticmethod def __extract_activities( - patient_journey_numbered: str, condition: Optional[str] + patient_journey_numbered: str, condition: Optional[str], number_of_senteces: int ) -> pd.DataFrame: """ Converts a Patient Journey, where every sentence is numbered, to a DataFrame with the activity labels by @@ -84,6 +84,12 @@ def __extract_activities( messages.append({"role": "user", "content": user_message}) activity_labels = u.query_gpt(messages).split("\n") df = pd.DataFrame(activity_labels, columns=[column_name]) - df[["activity", "sentence_id"]] = df["activity"].str.split(" #", expand=True) + try: + df[["activity", "sentence_id"]] = df["activity"].str.split( + " #", expand=True + ) + except ValueError: + scaling_factor = df.shape[0] / (number_of_senteces - 1) + df["sentence_id"] = df.reset_index().index * scaling_factor return df diff --git a/tracex_project/extraction/tests/test_orchestrator.py b/tracex_project/extraction/tests/test_orchestrator.py index 305b7a3e..c03a8522 100644 --- a/tracex_project/extraction/tests/test_orchestrator.py +++ b/tracex_project/extraction/tests/test_orchestrator.py @@ -118,7 +118,6 @@ def test_run(self): ) configuration.update( modules={ - "preprocessing": Preprocessor, "activity_labeling": ActivityLabeler, "cohort_tagging": CohortTagger, } diff --git a/tracex_project/extraction/tests/test_views.py b/tracex_project/extraction/tests/test_views.py index 383b2baa..af0d8cab 100644 --- a/tracex_project/extraction/tests/test_views.py +++ b/tracex_project/extraction/tests/test_views.py @@ -301,27 +301,6 @@ def test_get_context_data(self): self.assertIn("is_comparing", context) - # Non-deterministic test since orchestrator is executed - def test_form_valid(self): - """Test that a valid form submission redirects to the correct URL.""" - form_data = { - "modules_required": ["activity_labeling"], - "modules_optional": ["preprocessing", "event_type_classification"], - "event_types": ["Symptom Onset", "Symptom Offset"], - "locations": ["Home", "Hospital", "Doctors", "N/A"], - "activity_key": "event_type", - } - # Set up session data - session = self.client.session - session["is_comparing"] = False - session.save() - - # Submit the form using the test client - response = self.client.post(self.url, data=form_data) - - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, reverse("result")) - def test_get_ajax(self): """ Test the `get` method when an AJAX request is made. @@ -338,70 +317,3 @@ def test_get_ajax(self): self.assertEqual( json.loads(response.content), {"progress": 50, "status": "running"} ) - - -class ResultViewTests(TestCase): - """Test cases for the ResultView.""" - - fixtures = ["tracex_project/tracex/fixtures/dataframe_fixtures.json"] - - def setUp(self): # pylint: disable=invalid-name - """Set up test client, a mock Patient Journey, session data and the URL.""" - self.client = Client() - self.mock_journey = PatientJourney.manager.create( - name="Test Journey", patient_journey="This is a test Patient Journey." - ) - self.session = self.client.session - self.session["selected_modules"] = ["activity_labeling", "cohort_tagging"] - self.session.save() - self.url = reverse("result") - - def test_view_get_request(self): - """Test that the view URL exists and is accessible by passing a GET request.""" - response = self.client.get(self.url) - resolver = resolve(self.url) - - self.assertEqual(response.status_code, 200) - self.assertEqual(resolver.func.view_class, ResultView) - - def test_uses_correct_template(self): - """Test that the view uses the correct template.""" - response = self.client.get(self.url) - - self.assertTemplateUsed(response, "result.html") - - def test_uses_correct_form(self): - """Test that the view uses the correct form.""" - response = self.client.get(self.url) - - self.assertIsInstance(response.context["form"], ResultForm) - - def test_get_form_kwargs(self): - """Test that correct form kwargs are passed to the form.""" - response = self.client.get(self.url) - - self.assertEqual(response.status_code, 200) - - form = response.context["form"] - - self.assertIsInstance(form, ResultForm) - self.assertEqual( - (form.initial["selected_modules"]), self.session["selected_modules"] - ) - - def test_get_context_data(self): - """Test that the view fetches the correct context data.""" - response = self.client.get(self.url) - - self.assertEqual(response.status_code, 200) - - context = response.context - - self.assertIn("form", context) - self.assertIsInstance(context["form"], ResultForm) - self.assertIn("journey", context) - self.assertEqual(context["journey"], self.mock_journey.patient_journey) - self.assertIn("dfg_img", context) - self.assertIn("trace_table", context) - self.assertIn("all_dfg_img", context) - self.assertIn("event_log_table", context) diff --git a/tracex_project/tracex/fixtures/dataframe_fixtures.json b/tracex_project/tracex/fixtures/dataframe_fixtures.json index fccef76f7cb0bf31c6d0c425e357672687090c3c..48070174b35498491782ae7980484a7e3edb43d1 100644 GIT binary patch literal 158172 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 ah*AmIRwzi=e5ax+t&YpB(C_}^cmF?7TdTqV literal 307166 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

XrHqX{!Aye~BiRZ)Tt93+^)pao6@CY)(p<3SqbP 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Ν%<;%#S!n{j`p( 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 h2+>C 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 diff --git a/tracex_project/tracex/settings.py b/tracex_project/tracex/settings.py index b360e9a9..bdfbf6e2 100644 --- a/tracex_project/tracex/settings.py +++ b/tracex_project/tracex/settings.py @@ -12,8 +12,6 @@ from pathlib import Path -from tracex.logic import constants as c - # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent From c2fd0d83197247072e119c0be56847f71090fdf2 Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Mon, 27 May 2024 15:57:07 +0200 Subject: [PATCH 4/8] :fire: satisfy pylint --- tracex_project/extraction/tests/test_orchestrator.py | 1 - tracex_project/extraction/tests/test_views.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/tracex_project/extraction/tests/test_orchestrator.py b/tracex_project/extraction/tests/test_orchestrator.py index c03a8522..caaea5dc 100644 --- a/tracex_project/extraction/tests/test_orchestrator.py +++ b/tracex_project/extraction/tests/test_orchestrator.py @@ -5,7 +5,6 @@ from extraction.logic.orchestrator import ExtractionConfiguration, Orchestrator from extraction.logic.modules import ( - Preprocessor, ActivityLabeler, CohortTagger, ) diff --git a/tracex_project/extraction/tests/test_views.py b/tracex_project/extraction/tests/test_views.py index af0d8cab..7375c94c 100644 --- a/tracex_project/extraction/tests/test_views.py +++ b/tracex_project/extraction/tests/test_views.py @@ -9,7 +9,6 @@ JourneyUploadForm, JourneySelectForm, FilterForm, - ResultForm, ) from extraction.models import ( PatientJourney, @@ -20,7 +19,6 @@ JourneySelectView, JourneyDetailView, JourneyFilterView, - ResultView, ) From 197c64a169ae0ae399f3cfe6e312d109dd11311e Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Tue, 28 May 2024 11:50:18 +0200 Subject: [PATCH 5/8] :gem: fix ids in db --- tracex_project/db.sqlite3 | Bin 364544 -> 364544 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tracex_project/db.sqlite3 b/tracex_project/db.sqlite3 index a509afbe93274e3fa59bcf288e4d77ac137fb21d..1cc708e2b68138f61f160aea440080286c1a3fce 100644 GIT binary patch delta 34434 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

%mc#{lZj{>ige(e3gtE3NmAMi3c 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

U6MBt&Mg|<#@o}NxQvnhf5a> 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 delta 28223 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 Date: Fri, 31 May 2024 10:00:36 +0200 Subject: [PATCH 6/8] :gem: last fixes --- .../extraction/logic/modules/module_activity_labeler.py | 2 +- tracex_project/tracex/logic/constants.py | 1 - tracex_project/tracex/settings.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tracex_project/extraction/logic/modules/module_activity_labeler.py b/tracex_project/extraction/logic/modules/module_activity_labeler.py index ecb3228f..a1c9f540 100644 --- a/tracex_project/extraction/logic/modules/module_activity_labeler.py +++ b/tracex_project/extraction/logic/modules/module_activity_labeler.py @@ -90,6 +90,6 @@ def __extract_activities( ) except ValueError: scaling_factor = df.shape[0] / (number_of_senteces - 1) - df["sentence_id"] = df.reset_index().index * scaling_factor + df["sentence_id"] = int(df.reset_index().index * scaling_factor) return df diff --git a/tracex_project/tracex/logic/constants.py b/tracex_project/tracex/logic/constants.py index 881fe347..7ada56bd 100644 --- a/tracex_project/tracex/logic/constants.py +++ b/tracex_project/tracex/logic/constants.py @@ -25,7 +25,6 @@ MAX_TOKENS: Final = 1100 MODEL: Final = "gpt-3.5-turbo" OAIK: Final = os.environ.get("OPENAI_API_KEY") -DJANGO_SECRET_KEY: Final = os.environ.get("DJANGO_SECRET_KEY") TEMPERATURE_SUMMARIZING: Final = 0 TEMPERATURE_CREATION: Final = 1 THRESHOLD_FOR_MATCH: Final = 0.5 diff --git a/tracex_project/tracex/settings.py b/tracex_project/tracex/settings.py index bdfbf6e2..a5b0e3d4 100644 --- a/tracex_project/tracex/settings.py +++ b/tracex_project/tracex/settings.py @@ -23,7 +23,7 @@ DEBUG = True -ALLOWED_HOSTS = ["*"] +ALLOWED_HOSTS = [] # Application definition From 884cdfc0acc4a3269b61d819f31ca1db9f283faa Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Fri, 31 May 2024 11:03:03 +0200 Subject: [PATCH 7/8] :fire: implement changes requested by Pit --- .../extraction/logic/modules/module_activity_labeler.py | 4 +++- tracex_project/extraction/templates/filter_journey.html | 2 +- tracex_project/extraction/templates/journey_details.html | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tracex_project/extraction/logic/modules/module_activity_labeler.py b/tracex_project/extraction/logic/modules/module_activity_labeler.py index a1c9f540..7e714619 100644 --- a/tracex_project/extraction/logic/modules/module_activity_labeler.py +++ b/tracex_project/extraction/logic/modules/module_activity_labeler.py @@ -46,7 +46,9 @@ def execute( patient_journey_sentences ) activity_labels: pd.DataFrame = self.__extract_activities( - patient_journey_numbered, condition, len(patient_journey_sentences) + patient_journey_numbered=patient_journey_numbered, + condition=condition, + number_of_sentences=len(patient_journey_sentences), ) return activity_labels diff --git a/tracex_project/extraction/templates/filter_journey.html b/tracex_project/extraction/templates/filter_journey.html index 991ed348..7f59988a 100644 --- a/tracex_project/extraction/templates/filter_journey.html +++ b/tracex_project/extraction/templates/filter_journey.html @@ -332,7 +332,7 @@

DFG activity key

- + diff --git a/tracex_project/extraction/templates/journey_details.html b/tracex_project/extraction/templates/journey_details.html index c19a6ae0..aea158fd 100644 --- a/tracex_project/extraction/templates/journey_details.html +++ b/tracex_project/extraction/templates/journey_details.html @@ -17,7 +17,7 @@

Content of "{{ patient_journey.name }}"

- + From 7431423c54c677fb97d37ac289599912e19f744e Mon Sep 17 00:00:00 2001 From: Nils Schmitt Date: Fri, 31 May 2024 11:11:19 +0200 Subject: [PATCH 8/8] :fire: fix typo --- .../extraction/logic/modules/module_activity_labeler.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tracex_project/extraction/logic/modules/module_activity_labeler.py b/tracex_project/extraction/logic/modules/module_activity_labeler.py index 7e714619..bc8e97ec 100644 --- a/tracex_project/extraction/logic/modules/module_activity_labeler.py +++ b/tracex_project/extraction/logic/modules/module_activity_labeler.py @@ -70,7 +70,9 @@ def __number_patient_journey_sentences(patient_journey_sentences: List[str]) -> @staticmethod def __extract_activities( - patient_journey_numbered: str, condition: Optional[str], number_of_senteces: int + patient_journey_numbered: str, + condition: Optional[str], + number_of_sentences: int, ) -> pd.DataFrame: """ Converts a Patient Journey, where every sentence is numbered, to a DataFrame with the activity labels by @@ -91,7 +93,7 @@ def __extract_activities( " #", expand=True ) except ValueError: - scaling_factor = df.shape[0] / (number_of_senteces - 1) + scaling_factor = df.shape[0] / (number_of_sentences - 1) df["sentence_id"] = int(df.reset_index().index * scaling_factor) return df